Код, который вы предоставляете, очень неэффективен. Чтобы найти решение на сумму 63, представьте, что оно сначала вернется к целевой сумме с шагами наименьшей монеты (т.е. 1). Затем после большого количества возвратов и попыток с другими монетами, он, наконец, возвращается к внешнему уровню и пробует монету со значением 5. Теперь рекурсия запускается снова, как и раньше, добавляя монеты со значением 1. Но проблема в том, что это Промежуточное значение (63-5) уже посещалось ранее (на 5 уровней после выбора монеты 1), и потребовалось много вызовов функции, чтобы получить результаты для этого значения 58. И все же алгоритм просто проигнорирует это и выполнит все эта работа снова.
Распространенным решением для этого является динамическое программирование, то есть запоминание ранее найденных решений, чтобы их можно было повторно использовать без дополнительной работы.
Я представлю здесь восходящий метод: он сначала проверяет все суммы, которые могут быть достигнуты всего одной монетой. Эти суммы помещаются в очередь. Если цель находится среди них, то ответ равен 1. Если нет, все суммы в очереди обрабатываются путем добавления всех возможных монет к каждой из них. Иногда будет найдено значение, которое уже было посещено ранее, и в этом случае оно не будет помещено в следующую очередь, но в противном случае это так. Если теперь целевое значение находится в этой очереди, вы знаете, что цель может быть достигнута всего за 2 монеты.
Этот процесс продолжается в цикле, который на самом деле является просто поиском по ширине в дереве, где суммы являются узлами, а ребра представляют, что одна сумма может быть достигнута из другой, добавив к ней одну монету. Поиск начинается в узле, представляющем сумму 0.
Вот код для этого:
def rec_coin(target, coins):
visited = set() # Amounts that we have already achieved with a minimal number of coins
amounts = [0] # The latest series of amounts all using an equal number of coins
for min_coins in range(1, target+1):
next_amounts = []
for amount in amounts:
for coin in coins:
added = amount + coin
if added == target:
return min_coins
if not added in visited:
visited.add(added)
next_amounts.append(added)
amounts = next_amounts
print (rec_coin(63,[1,5,10,25]))