Greedy Algoritm 적용문제
큰 수의 법칙
큰 수의 법칙은 통계분야에서 다뤄지는 내용으로 다양한 수로 이루어진 배열이 있을 때 주어진 수들을 M번 더하여 가장 큰 수를 만드는 법칙이다. 단 배열의 특정한 인덱스(번호)에 해당하는 수가 연속으로 K번 초과해 더해질 수 없다는 특징이 있다.
예를 들어 순서대로 2,4,5,4,6로 이루어진 배열이 있을 때 M이 8이고 K가 3이라고 가정할때 특정한 인덱스의 수가 연속해서 세 번까지만 더해질 수 있으므로 6+6+6+5+6+6+6+5인 45이 된다. 단, 서로 다른 인덱스에 해당하는 수가 같은 경우에도 서로 다른 것으로 간주한다. 3,4,3,4,3,으로 이루어진 배열이 있고, M이 7이고 K가 2라고 가정하자. 이 때 4는 두번째, 네번째 원소이므로 번갈아 두번씩 더해 4+4+4+4+4+4+4인 28이 도출된다.
문제
- 첫째 줄에 N(2 =< N =< 1000), M(2 =< M =< 1000), K(2 =< K =< 1000)의 자연수가 주어지며 각 자연수는 공백으로 구분한다.
- 둘째 줄에 N개의 자연수가 주어진다. 각 자연수는 공백으로 구분한다. 단, 각각의 자연수는 1 이상 10000이하의 수로 주어진다.
- 입력으로 주어지는 K는 항상 M보다 작거나 같다.
코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
n,m,k = map(int,input().split())
data = list(map(int,input().split()))
data.sort()
first = data[n-1]
second = data[n-2]
result = 0
while True:
for i in range(k):
if m==0:
break
result += first
m-=1
if m ==0:
break
result += second
m-=1
print(result)
그렇다면 가장 큰 수가 몇번 더해졌는지 어떻게 알 수 있을까? 큰수는 K번씩 반복되며 그다음 큰수 한번을 더한 K+1의 횟수로 반복되게 된다. 그렇기 때문에 반복 횟수 M을 K+1로 나눠주면 수열이 몇번 들어있는지 알 수 있고, 해당 수열마다 K번씩 있으므로 K를 곱해준다. 또한 M을 K+1로 나눈 나머지 값만큼의 K가 사용된다. 즉 다음의 코드와 같이 구하면 된다.
코드
1
2
3
4
5
6
7
count = int(m/(k+1)) * k
count += m%(k+1)
#만약 가장 큰 수만 더한다면?
result += (count)*data[n-1]
#만약 두번째로 큰 수만 더한다면?
result += (m-count)*data[n-2]
숫자 카드 게임
숫자 카드 게임은 여러 카드 중 가장 높은 숫자 카드를 뽑는 게임이며 룰은 다음과 같다.
- 숫자가 쓰인 카드들이 N x M 형태로 놓여 있다. 이때 N은 행의 개수, M은 열의 개수이다.
- 먼저 뽑고자 하는 카드가 포함되어 있는 행을 선택한다.
- 그 다음 선택된 행에 포함된 카드들 중 가장 낮은 카드를 뽑아야 한다.
- 따라서 처음에 카드를 골라낼 행을 선택할 때, 이후에 해당 행에서 가장 낮은 숫자가 낮은 카드를 뽑는 것을 고려하여 최종적으로 가장 높은 숫자의 카드를 뽑을 수 있도록 전략을 세워야 한다.

문제
- 첫째 줄에 숫자 카드들이 놓인 행의 개수 N과 열의 개수 M이 공백을 기준으로 하여 각각 자연수로 주어진다.(1 =< N,M =< 100)
- 둘째 줄부터 N개의 줄에 걸쳐 각 카드에 적힌 숫자가 주어진다. 각 숫자는 1이상 10000이하의 자연수이다.
이 문제는 각 행마다 작은 수를 찾은 다음, 그 중에서 가장 큰 수를 찾는 것이다. 그냥 각각의 행을 Sort해서 첫번째 인자들 끼리 비교하면 될 것 같다.
코드
1
2
3
4
5
6
7
8
9
n,m = map(int,input().split())
result = 0
for i in range(n):
data = list(map(int,input().split()))
min_value = min(data)
result = max(result,min_value)
print(result)
1이 될 때까지
어떠한 수 N이 1이 될 때까지 다음의 두 과정 중 하나를 반복적으로 선택하여 수행하려고 한다. 단, 두 번째 연산은 N이 K로 나누어떨어질 때만 선택할 수 있다.
- N에서 1을 뺀다.
- N을 K로 나눈다.
문제
- 첫째 줄에 N(2 =< N =< 100000)과 K(2 =< K =< 100000)가 공백으로 구분되며 각각 자연수로 주어진다. 이 때 N은 K보다 크거나 같다.
- 이 때 N이 1이 되는 최소 회수를 구하라.
코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
n,k = map(int,input().split())
count = 0
while True:
if n == 1:
break
elif (n % k) == 0:
n //= k
count += 1
else :
n -= 1
count +=1
print(count)
Comments