Вот мое решение, снова на Python и с использованием динамического программирования.Сначала я генерирую минимальную последовательность монет, необходимую для внесения изменений для каждой суммы в диапазоне 1..99, и из этого результата я нахожу максимальное количество монет, необходимое для каждого номинала:
def min_any_change():
V, C = [1, 5, 10, 25], 99
mxP, mxN, mxD, mxQ = 0, 0, 0, 0
solution = min_change_table(V, C)
for i in xrange(1, C+1):
cP, cN, cD, cQ = 0, 0, 0, 0
while i:
coin = V[solution[i]]
if coin == 1:
cP += 1
elif coin == 5:
cN += 1
elif coin == 10:
cD += 1
else:
cQ += 1
i -= coin
if cP > mxP:
mxP = cP
if cN > mxN:
mxN = cN
if cD > mxD:
mxD = cD
if cQ > mxQ:
mxQ = cQ
return {'pennies':mxP, 'nickels':mxN, 'dimes':mxD, 'quarters':mxQ}
def min_change_table(V, C):
m, n, minIdx = C+1, len(V), 0
table, solution = [0] * m, [0] * m
for i in xrange(1, m):
minNum = float('inf')
for j in xrange(n):
if V[j] <= i and 1 + table[i - V[j]] < minNum:
minNum = 1 + table[i - V[j]]
minIdx = j
table[i] = minNum
solution[i] = minIdx
return solution
Выполнение min_any_change()
дает ответ, который мы искали: {'pennies': 4, 'nickels': 1, 'dimes': 2, 'quarters': 3}
.В качестве теста мы можем попробовать удалить монету любого достоинства и проверить, можно ли еще внести изменения для любой суммы в диапазоне 1..99:
from itertools import combinations
def test(lst):
sums = all_sums(lst)
return all(i in sums for i in xrange(1, 100))
def all_sums(lst):
combs = []
for i in xrange(len(lst)+1):
combs += combinations(lst, i)
return set(sum(s) for s in combs)
Если мы проверим полученный выше результатмы получаем True
:
test([1, 1, 1, 1, 5, 10, 10, 25, 25, 25])
Но если мы уберем одну монету, независимо от номинала, мы получим False
:
test([1, 1, 1, 5, 10, 10, 25, 25, 25])