假设我有一组面额为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问题
答案 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];
}