当前位置: 首页 > 知识库问答 >
问题:

硬币变化递归解

东门楚
2023-03-14

给定一个值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]

我的递归关系对吗?

共有1个答案

商璞
2023-03-14

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

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

我认为您的思路是正确的,但我建议您只需删除中间维度[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美分的方法数量)

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

public static int combinations(int numCoinsToUse, int targetSum, int[] denom) {
    // dp[numCoins][sum]  ==  ways to get sum using numCoins
    int[][] dp = new int[numCoinsToUse+1][targetSum];

     // Any sum (except 0) is impossible with 0 coins
     for (int sum = 0; sum < targetSum; sum++) {
         dp[0][sum] = sum == 0 ? 1 : 0;
     }

     // Gradually increase number of coins
     for (int c = 1; c <= numCoinsToUse; c++)
         for (int sum = 0; sum < targetSum; sum++)
             for (int d : denom)
                 if (sum >= d)
                     dp[c][sum] += dp[c-1][sum - d];
     return dp[numCoinsToUse][targetSum-1];
 }

使用示例输入:

 类似资料:
  • 我试图用递归来解决硬币兑换问题,遇到了下面的代码。 问题:给定一些面额的无限硬币,计算它们形成给定数量的方式。 输入: 代码: 我理解代码本身,也理解基本情况,但是我不理解它是如何封装递归/解决方案的。 例如,如果我正在求解,我可以说,因此我可以清楚地“看到”递归。在换硬币的例子中,我无法推断出类似的关系。有人能帮我吗?

  • 我需要编写一个算法,它接收一个数字和一个数字列表,并从列表中返回可能的数字组合的数量,从而可以创建和数。例如:def coin(5,[1,2,5,6]应该返回数字4,因为列表中有4种可能的组合可以一起创建数字5。下面是我尝试过的代码,但它不起作用。输出是6而不是4,我希望您能帮助我理解为什么。

  • 我已经编写了一个代码,用来计算使用递归从1到100之间的任何值可以得到的更改可能性的数量。我不确定项目中的2个方法做了什么(代码中的粗体部分),所以有人能给我解释一下吗?我对Java还很陌生。 我包含了上下文的整个代码,但不确定是否有必要。

  • 我见过很多硬币更换问题,这个问题很独特。我尝试使用DP和递归,但我无法解决它。 这就是问题所在: 假设给定一个价格,X,其中X是美分,我有5种有限面额的硬币,1,5,10,20,50。我有不同数量的1、5、10、20、50分硬币。我想用最大数量的硬币来确定价格X。我该怎么做?(假设X总是可以用手头的硬币制作) 例如,如果价格X=52,并且 我有三枚一分硬币 我有四枚五分硬币 我有8枚10美分的硬币

  • 问题:我很难找到达到特定金额所需的最低硬币数量。我很确定这是最简单的递归方式,使用动态编程方法,我基本上应该得到Math.min(“获取ACoin”、“离开ACoin”);不幸的是,我的代码不会终止,尽管我确实有在满足总和的条件下终止的if语句,硬币数组耗尽,或者如果总和结束。请查看下面的代码,让我知道我做错了什么,特别是为什么我的代码继续执行,直到它收到一个stackoverflow错误,尽管我

  • 我目前正在尝试用Python实现动态编程,但我不知道如何设置回溯部分,使其不会重复排列。例如,一个输入应该是(6,[1,5]),预期的输出应该是2,因为有两种可能的方式来排列1和5,使它们的总和等于6。这些组合是{1,1,1,1,1}和{1,5}但是我的程序目前的工作方式,它考虑了上面显示的组合和组合{5,1}。这导致输出为3,这不是我想要的。所以我的问题是“如何防止重复排列?”。我当前的代码如下