硬币改变算法

时间:2009-12-31 19:36:18

标签: algorithm

假设我有一组面额为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.

注意:不做作业只是修改this问题

3 个答案:

答案 0 :(得分:21)

这是一个经典的动态编程问题(请注意,贪婪算法并不总是在这里工作!)。

假设硬币是按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 Problem 67

答案 1 :(得分:0)

这是Python中动态编程算法的示例实现。它比Jason描述的算法简单,因为它只计算他描述的2D表的1行。

请注意,使用此代码作弊作业将使Zombie Dijkstra哭泣。

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)

答案 2 :(得分:-1)

以下是动态规划的自底向上方法。

        int[] dp = new int[amount+ 1]; 
        Array.Fill(dp,amount+1);
        dp[0] = 0;
        for(int i=1;i<=amount;i++)
        {
            for(int j=0;j<coins.Length;j++)
            {
                if(coins[j]<=i) //if the amount is greater than or equal to the current coin
                {
                    //refer the already calculated subproblem dp[i-coins[j]]
                    dp[i] = Math.Min(dp[i],dp[i-coins[j]]+1);
                }
            }
        }
        if(dp[amount]>amount)
            return -1;
        return dp[amount];
    }