动态规划硬币变化问题

时间:2015-03-07 03:12:39

标签: algorithm dynamic-programming coin-change

我遇到了解决各种问题的动态编程解决方案的问题,特别是硬币更改问题:

“给定值N,如果我们想要改变N美分,并且我们每个S = {S1,S2,..,Sm}价值硬币都有无限供应,我们可以通过多少方式进行更改?硬币的顺序无关紧要。

例如,对于N = 4和S = {1,2,3},有四个解:{1,1,1,1},{1,1,2},{2,2}, {1,3}。因此输出应为4.对于N = 10且S = {2,5,3,6},有五种解决方案:{2,2,2,2,2},{2,2,3,3}, {2,2,6},{2,3,5}和{5,5}。所以输出应该是5。“

此问题还有另一种变化,即解决方案是满足金额的最小硬币数量。

这些问题看起来非常相似,但解决方案非常不同

进行更改的可能方式:最佳子结构为 DP(m,n)= DP(m-1,n)+ DP(m,n-Sm)其中DP是所有硬币直到第m个硬币的解决方案的数量,金额= n。

最小硬币数量:这是最佳的子结构 DP [i] = Min {DP [i-d1],DP [i-d2],... DP [i-dn]} + 1 其中i是总量,d1 .. dn代表每个硬币面额。

为什么第一个需要2-D阵列而第二个需要1-D阵列?为什么改变方式的最佳子结构不是“ DP [i] = DP [i-d1] + DP [i-d2] + ... DP [i-dn] “其中DP [i]是我可以通过硬币获得金额的方式。这对我来说听起来很合乎逻辑,但却产生了错误的答案。为什么这个问题需要硬币的第二个维度,但在最小量问题中不需要?

问题的链接:

http://comproguide.blogspot.com/2013/12/minimum-coin-change-problem.html http://www.geeksforgeeks.org/dynamic-programming-set-7-coin-change/

提前致谢。我去的每个网站只解释解决方案的工作原理,而不是其他解决方案不起作用的原因。

2 个答案:

答案 0 :(得分:5)

  1. 让我们先谈谈道路的数量, DP(m,n)= DP(m-1,n)+ DP(m,n-Sm)。这确实是正确的,因为要么你可以使用mth面额,要么你可以避免它。现在你说为什么我们不把它写成 DP [i] = DP [i-d1] + DP [i-d2] + ... DP [i-dn] 。那么这将导致过度计数,让我们举个例子,其中n = 4 m = 2且S = {1,3}。现在根据你的解决方案dp [4] = dp [1] + dp [3]。 (假设1是基本情况dp [1] = 1)。现在dp [3] = dp [2] + dp [0]。 (再次基础情况下dp [0] = 1)。再次应用相同的dp [2] = dp [1] = 1。因此总的来说,当它应该只是2((1,3)和(1,1,1,1))时你会得到3的答案。它是因为 你的第二种方法将(1,3)和(3,1)视为两种不同的解决方案。你的第二种方法可以应用于订单重要的情况,这也是一个标准问题。
  2. 现在谈谈你的第二个问题,你说最少的面额可以 通过 DP [i] = Min {DP [i-d1],DP [i-d2],... DP [i-dn]} + 1 找到。这是正确的,因为在寻找最小面额时,订单或没有订单无关紧要。为什么这是线性/ 1-D DP,尽管DP阵列是1-D,但每个状态依赖于最多m个状态,这与第一个解决方案不同,其中阵列是2-D但每个状态最多取决于2个状态。因此,在两种情况下,运行时间(状态数*每个状态所依赖的状态数)与 O(nm)相同。所以两者都是正确的,只是你的第二个解决方案可以节因此,您可以通过1-D数组方法或2-D通过使用重复来找到它 的 DP(N,M)= MIN(DP(M-1,N),1个+ DP(M,N-SM))即可。 (只需在第一次复发时使用min)


    希望我清除了疑虑,如果还有不清楚的话,请发帖。

答案 1 :(得分:0)

This是使用动态编程解决硬币变化问题的一个非常好的解释。

代码如下:

public static int change(int amount, int[] coins){
    int[] combinations = new int[amount + 1];

    combinations[0] = 1;

    for(int coin : coins){
        for(int i = 1; i < combinations.length; i++){
            if(i >= coin){
                combinations[i] += combinations[i - coin];
                //printAmount(combinations);
            }
        }
        //System.out.println();
    }

    return combinations[amount];
}