【问题标题】:Number of ways to make change for amount N更改金额 N 的方法数
【发布时间】:2014-10-28 16:56:13
【问题描述】:

我遇到了这个问题:

http://www.geeksforgeeks.org/dynamic-programming-set-7-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。

我想出了解决方案:

// recurrence relation
count[N] = count[N-d] for all denomination <= N

Source code
-----------

public static int numWays(int N, int[] denoms) {
  if (N == 0)
     return 0;
  
  int[] ways = new int[N+1];
  ways[0] = 1;
  
  for (int i=1; i<=N; i++) {
     ways[i] = 0;
     for (int d : denoms) {
        if (d <= i) {
           ways[i] += ways[i-d];
        }
     }
  }
  
  return ways[N];
}

但这会计算具有相同面额但顺序不同的重复项。例如,如果面额 = {1,2} 且 N=3,则计算 {1,1,1}、{2,1}、{1,2} 中的重复条目 {1,2}。

我看到链接here 中描述的DP 解决方案避免了重复。我了解递归关系是如何工作的,但我无法理解它如何能够避免重复,而我的解决方案不是。请解释背后的想法。

【问题讨论】:

    标签: algorithm dynamic-programming


    【解决方案1】:

    C(i, j) 使用面额硬币S1, ..., Sj 计算出总数i 的方法数。您的代码实现了以下重复(有序方式)。

    C(i, m) | i <  0 = 0
            | i == 0 = 1
            | i >  0 = sum_{j = 1}^m C(i - Sj, m)
    

    链接的代码实现了不同的循环(无序方式)。

    C(i, j) | i <  0           = 0
            | i == 0           = 1
            | i >  0 && j <= 0 = 0
            | i >  0 && j >  0 = C(i - Sj, j) + C(i, j - 1)
    

    这两个代码之间的区别很微妙:或多或少只是循环的嵌套方式。你的添加了i 的所有术语,然后再转到i + 1,但链接代码为每个i 添加了j 术语,然后为每个i 添加了j + 1 术语,等等。结果,当链接代码考虑使用小计i 中的面额-Sj 硬币的可能性时,它隐含地只考虑那些继续使用面额硬币S1, ..., Sj 的解决方案,因为i - Sj 的当前总数确实不包括使用其他硬币的可能性。

    【讨论】:

      猜你喜欢
      • 2011-11-30
      • 2013-01-16
      • 2022-01-11
      • 2013-11-12
      • 1970-01-01
      • 1970-01-01
      • 2015-10-11
      • 2017-07-17
      • 2020-10-02
      相关资源
      最近更新 更多