【问题标题】:coin change recurrence solution硬币找零重复解决方案
【发布时间】:2015-09-02 05:38:08
【问题描述】:

给定一个 N 值,如果我们想找 N 美分,并且我们有无限供应 S = { S1, S2, .. , Sm} 价值的硬币,我们有多少种方法可以找零?硬币的顺序无关紧要。不过还有一个额外的限制:你只能用恰好 K 个硬币来找零。

例如,对于 N = 4、k = 2 和 S = {1,2,3},有两种解:{2,2},{1,3}。所以输出应该是2。

解决方案:

int getways(int coins, int target, int total_coins, int *denomination, int size, int idx)
    {
            int sum = 0, i;
            if (coins > target || total_coins < 0)
                    return 0;
            if (target == coins && total_coins == 0)
                    return 1;
            if (target == coins && total_coins < 0)
                    return 0;
            for (i=idx;i<size;i++) {
                    sum += getways(coins+denomination[i], target, total_coins-1, denomination, size, i);
            }
            return sum;
    }

    int main()
    {
            int target = 49;
            int total_coins = 15;
            int denomination[] = {1, 2, 3, 4, 5};
            int size = sizeof(denomination)/sizeof(denomination[0]);
            printf("%d\n", getways(0, target, total_coins, denomination, size, 0));
    }

以上是递归解决方案。但是我需要动态编程解决方案的帮助:

dp[i][j][k] 代表ij 元素和k 硬币的总和。

所以,

dp[i][j][k] = dp[i][j-1][k] + dp[i-a[j]][j][k-1]

我的循环关系对吗?

【问题讨论】:

  • 应该和普通的硬币找零问题一模一样,但是剩下的硬币数量是一位数。我很惊讶你有一个 3D dp 矩阵。普通的硬币链通常是一维的,如果有一个额外的硬币,你应该最终得到一个二维矩阵。我想我想问的是 "j elements" 是什么意思?
  • @aioobe: j 是数组的索引。
  • 是的,但它代表什么。 k代表硬币数量,j代表什么?
  • @aioobe: algorithmist.com/index.php/Coin_Change 看看这个。
  • 对。但仅仅因为你有 3 个嵌套循环并不一定意味着你需要一个 3D dp。

标签: dynamic-programming recurrence


【解决方案1】:

我不太明白你的重复关系:

dp[i][j][k]j 元素和k 硬币代表i 的总和。

我认为你在正确的轨道上,但我建议简单地删除中间维度[j],并使用dp[sum][coinsLeft],如下所示:

dp[0][0] = 1  // coins: 0, desired sum: 0  =>  1 solution
dp[i][0] = 0  // coins: 0, desired sum: i  =>  0 solutions

dp[sum][coinsLeft] = dp[sum - S1][coinsLeft-1]
                   + dp[sum - S2][coinsLeft-1]
                   + ...
                   + dp[sum - SM][coinsLeft-1]

然后可以在dp[N][K] 找到答案(= 添加 K 个硬币以获得 N 美分的方法数)

这是一些示例代码(我建议您在尝试自己解决之前不要查看。这是一个很好的练习):

公共静态整数组合(int numCoinsToUse,int targetSum,int [] denom){
    // dp[numCoins][sum] == 使用 numCoins 获得总和的方法
    int[][] dp = new int[numCoinsToUse+1][targetSum];

     // 0 个硬币不可能有任何总和(0 除外)
     for (int sum = 0; sum = d)
                     dp[c][sum] += dp[c-1][sum - d];
     返回 dp[numCoinsToUse][targetSum-1];
 }

使用您的示例输入:

combinations(2, 4, new int[] {1, 2, 3} ) // gives 2

【讨论】:

  • 您的重复是正确的!您可以删除中间的 j 因为看到当您到达任何 DP[i][k] 时,它将具有 DP[i][j-1][k] 的值,而第二部分是一个较小的第 j 个子问题,即它将在当前问题之前计算,这意味着已经为第 j 个元素计算了 DP[ia[j]][k]!因此可以去掉中间的 j
  • 这也是我的理解。
猜你喜欢
  • 2015-03-08
  • 2013-12-09
  • 1970-01-01
  • 2022-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-01
相关资源
最近更新 更多