Для фиксированного набора S = {2, 5, 10}
решение довольно простое:
Нет решений для N=1,3
если N нечетное, вы должны использовать 5 - поэтому N=N-5
Теперь используйте жадный подход: получите как можно больше 10-секунд, затем как можно больше 2-х
def best(N):
print(N, end = ": ")
if (N % 2):
print("5", end = " ")
N = N - 5
if N >= 10:
print("10*", N//10, end = " ")
N = N % 10
if N > 1:
print("2*", N//2, end = " ")
21: 5 10* 1 2* 3
22: 10* 2 2* 1
23: 5 10* 1 2* 4
24: 10* 2 2* 2
В общем, вы можете найти оптимальное решение, используя динамическое c программирование.
Первый способ - это «мемоизация» - нужно реализовать рекурсивный подход с выбором лучшего решения, а затем добавить хранение промежуточных результатов в hashmap или другой структуре. Простая реализация:
S = [2, 3, 5, 7, 11]
dic = {}
def rec(summ):
if summ == 0:
return 0
rd = dic.get(summ)
if rd != None:
return rd
minn = 9999999999999
for s in S:
if s <= summ:
minn = min(minn, 1 + rec(summ - s))
dic[summ] = minn
return minn
N = 1000
print(rec(N))
>>92
Другой способ - использовать таблицу - вы заполняете ее с наилучшими возможными результатами, используя первый элемент, затем обновляете решение, используя второй элемент, и так далее.
Псевдокод
make int array A of size N+1
make int array P of size N+1
fill A[] with large value (MaxInt` or at least `N/min(S))
A[0] = 0
for s in S: //coin value
for (i = s; i <= N; i++)
if A[i - s] < A[i] + 1 //using this coin we can get better result for sum i
A[i] = A[i - s] + 1
P[i] = s //write down coin for this sum
Теперь у нас есть A[N]
с лучшим счетом, и мы можем получить необходимые монеты, используя последовательность P[N], P[N - P[N]]...
.
Рабочий Python код
S = [2, 3, 5, 7, 11]
N = 17
A = [0] + [10000] * N
P = [0] * (N + 1)
for s in S: #coin value
for i in range(s, N + 1):
if A[i - s] < A[i] + 1: #using this coin we can get better result for sum i
A[i] = A[i - s] + 1
P[i] = s #write down coin for this sum
print(A) #for reference
i = N
while i > 0:
print(P[i], end = " ")
i = i - P[i]
>> [0, 10000, 1, 1, 2, 1, 2, 1, 2, 2, 2, 1, 2, 2, 2, 3, 2, 3]
>> 11 3 3
Примечание - если мы можем использовать каждую монету только один раз, мы должны сделать внутренний l oop в обратном направлении, чтобы избежать многократного добавления одной и той же монеты