[알고리즘] 동전 2

난이도

Gold 4

문제

n가지 종류의 동전이 있다. 이 동전들을 적당히 사용해서, 그 가치의 합이 k원이 되도록 하고 싶다. 그러면서 동전의 개수가 최소가 되도록 하려고 한다. 각각의 동전은 몇 개라도 사용할 수 있다.

입력

첫째 줄에 n, k가 주어진다. (1 ≤ n ≤ 100, 1 ≤ k ≤ 10,000) 다음 n개의 줄에는 각각의 동전의 가치가 주어진다. 동전의 가치는 100,000보다 작거나 같은 자연수이다. 가치가 같은 동전이 여러 번 주어질 수도 있다.

출력

첫째 줄에 사용한 동전의 최소 개수를 출력한다. 불가능한 경우에는 -1을 출력한다.

예제 입력

3 15
1
5
12

예제 출력

3

해설

배낭 문제와 비슷한 형식의 문제이다. 일반적으로 거스름돈 문제는 Greedy하게 O(K)정도 수준으로(거스름돈의 종류에만 의존하므로) 어주 빠르게 해결할 수 있었는데, 이 문제는 동전간의 관계가 배수가 아니므로 DP로 해결해야 한다. 그렇기 때문에 동전의 조합으로 만들어낼 수 없는 값도 존재하는데, 그럴 때에 -1을 출력해야 한다. 나는 바텀 업 방식으로 풀이하면서 해당 d리스트 인덱스에 해당하는 가치를 만들 수 없을 경우 매우 큰 수를 대입하도록 하여 해결했다. 동전의 가치의 한계가 정해져 있으므로 정당한 풀이 방식이라고 생각한다.

제출 코드

import sys

n,m = map(int, sys.stdin.readline().rstrip().split())
coins = [] #화폐 단위
for i in range(n):
    coins.append(int(sys.stdin.readline().strip()))


d = [0 for i in range(m+1)]
for i in range(min(coins)):
    d[i] = 9999999 #방법이 없으므로

for i in range(min(coins),m+1):
    #print(d)
    if(i in coins):
        d[i] = 1
        continue
    minVal = 9999999
    for j in coins:
        if(i-j>=0):
            if(minVal > d[i-j]):
                minVal = d[i-j] + 1
    d[i] = minVal

#print(d)
if(d[m] >= 9999999):
    print('-1')
else:
    print(d[m])