动态编程用于硬币交换的变体

时间:2018-01-24 12:34:58

标签: 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. See here以获取更多详细信息。

Here,可以找到针对此问题的基于制表-DP的解决方案。此解决方案基于以下重现关系:

count(S, m, n) = count(S, m - 1, n) + count(S, m, n - S[m - 1]);

基础案例:

count(S, m, n < 0) = 0
count(S, m, n = 0) = 1
count(S, m <= 0, n >= 1) = 0

直观地说,这种递归关系将问题定义为两个子问题的解决方案:我们丢弃硬币的那些问题,以及我们假设硬币在当时逐步使用的问题。

问题:如何修改此递归关系以计算我们可以总结为 N 的方式,忽略顺序和偶数个加数?例如,对于 N = 4且 S = {1,2,3} ,总共有四个解决方案(忽略顺序):{1,1,1,1 },{1,1,2},{2,2},{1,3},但只有3个具有偶数个加数,即{1,1,1,1},{2,2} ,{1,3}。

之前的研究:起初我以为我可以将丢弃硬币的情况加倍,并要求每个硬币在我们使用某些硬币的情况下被消耗两次,即:

count(S, m, n) = count(S, m - 1, 2*n) + count(S, m, n - 2*S[m - 1]);

这适用于某些示例案例,但它不起作用。任何提示?

1 个答案:

答案 0 :(得分:0)

您需要在递归中添加一个标志,该标志是目前使用的加数数量的奇偶校验。

使用加数时,您可以翻转标记(S(n-v[m],m,!parity))。

基本案例是:

n=0 parity=0 -> 1

n=0 parity=1 -> 0

n<0 or m<0 (array is 0-indexed) -> 0

下面是c ++中的递归函数。当然,你需要记住它才能使它更有价值。

int S(int n,int m,bool parity)
{
    if (n==0)
    {
        if (parity==1)
            return 0;
        else 
            return 1;
    }
    if (m<0 || n<0)
        return 0;
    return S(n,m-1,parity)+S(n-v[m],m,!parity);
}