【问题标题】:Dynamic Programming for a variant of the coin exchange硬币交换变体的动态编程
【发布时间】:2018-01-24 12:34:57
【问题描述】:

我有兴趣解决硬币交换问题的变体。回想一下硬币交换问题的正式定义:

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

这适用于某些示例案例,但它不起作用。有什么提示吗?

【问题讨论】:

  • 我猜您可以使用两个单独的函数来使用奇数和偶数:o(S,m,n)= o(m-2, n)+e(m, n-s[m-1])e(S,m,n)= e(m-2, n)+o(m, n-s[m-1]),基数为:o(S, m, n &lt; 0) = 0 o(S, m, n = 0) = 0 o(S, m &lt;= 0, n &gt;= 1) = 0e(S, m, n &lt; 0) = 0 e(S, m, n = 0) = 1 e(S, m &lt;= 0, n &gt;= 1) = 0

标签: dynamic-programming coin-change


【解决方案1】:

您需要在递归中添加一个标志,该标志是迄今为止使用的和数的奇偶校验。

使用 summand 时,您会翻转标志 (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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多