Алгоритм смены монет

Предположим, что у меня есть набор монет, имеющих наименования a1, a2,... ak.

Известно, что один из них равен 1.

Я хочу сделать изменение для всех целых чисел от 1 до n, используя минимальное количество монет.

Любые идеи для алгоритма.

eg. 1, 3, 4 coin denominations
n = 11
optimal selection is 3, 0, 2 in the order of coin denominations.

n = 12
optimal selection is 2, 2, 1.

Примечание: не домашняя работа просто модификация эта проблема

Ответ 1

Это классическая проблема динамического программирования (заметим сначала, что жадный алгоритм здесь не всегда работает!).

Предположим, что монеты упорядочены так, что a_1 > a_2 > ... > a_k = 1. Мы определяем новую задачу. Мы говорим, что проблема (i, j) заключается в том, чтобы найти минимальное количество монет, внесших изменения для j, используя монеты a_i > a_(i + 1) > ... > a_k. Задача, которую мы хотим решить, (1, j) для любого j с 1 <= j <= n. Скажем, что C(i, j) является ответом на проблему (i, j).

Теперь рассмотрим экземпляр (i, j). Мы должны решить, используем ли мы одну из монет a_i. Если это не так, мы просто решаем проблему (i + 1, j), а ответ - C(i + 1, j). Если да, то мы завершим решение, сделав замену для j - a_i. Чтобы сделать это, используя как можно меньше монет, мы хотим решить проблему (i, j - a_i). Мы организуем так, чтобы эти две проблемы были решены для нас, а затем:

C(i, j) = C(i + 1, j)                         if a_i > j
        = min(C(i + 1, j), 1 + C(i, j - a_i)) if a_i <= j

Теперь выясните, что такое начальные случаи и как перевести это на выбранный вами язык, и вам должно быть хорошо идти.

Если вы хотите попробовать свои силы в другой интересной проблеме, требующей динамического программирования, посмотрите Project Euler Проблема 67.

Ответ 2

Здесь приведен пример реализации алгоритма динамического программирования в Python. Это проще, чем алгоритм, описанный Джейсоном, поскольку он вычисляет только одну строку 2D-таблицы, которую он описывает.

Обратите внимание, что использование этого кода, чтобы обмануть домашнюю работу, заставит зомби Дейкстра кричать.

import sys
def get_best_coins(coins, target):
    costs = [0]
    coins_used = [None]
    for i in range(1,target + 1):
        if i % 1000 == 0:
            print '...', 
        bestCost = sys.maxint
        bestCoin = -1
        for coin in coins:
            if coin <= i:
                cost = 1 + costs[i - coin]
                if cost < bestCost:
                    bestCost = cost
                    bestCoin = coin
        costs.append(bestCost)
        coins_used.append(bestCoin)
    ret = []    
    while target > 0:
        ret.append(coins_used[target])
        target -= coins_used[target]
    return ret

coins = [1,10,25]
target = 100033
print get_best_coins(coins, target)