【问题标题】:Coin change with limited number of coins硬币数量有限的硬币变化
【发布时间】:2011-05-11 00:54:39
【问题描述】:

我编写了一个程序来生成子集总和,它可能会用于这个问题,它指出:

假设,你有 3 个 1 美元硬币,2 个 2 美元硬币、3 个 5 美元硬币、1 个 10 美元硬币、 有 4 种方法可以获得 10 美元 那些硬币。如果有 n1 $X1 硬币,n2 $X2 硬币.... nm $Xm 硬币, 我们可以通过多少种方式获得 $X 这些硬币数量有限?

如果我们创建一组 { X1, X1..... X1, X2, X2.......... X2, ..., ..., .... ....., Xm, Xm... Xm},然后对它运行子集求和,当然我们可以得到 $X 的结果。 但我找不到使用集合 {n1, n2, n3.... nm} , {X1, X2, X3.... Xm} 的方法。 一个朋友告诉我这是背包问题的变体,但我不确定如何。

这是我写的部分代码:

ways[0]=1, mylim=0;
for(i=0;i<count;i++){
    if(mylim+coins[i]<=LIMIT) mylim+=coins[i];
    else mylim=LIMIT;

    for(j=mylim; j>=coins[i];j--){
        ways[j]=(ways[j]+ways[j-coins[i]])%MOD;
    }
}

如果你能详细解释一下,我会很好。

编辑: 这个问题更适合计算机科学的stackexchange,但由于这是我的一个老问题,我宁愿在这里编辑它。

这个问题可以通过包含排除原则来解决,当我们有固定硬币值但每个硬币的数量随每次查询而变化时,它会派上用场。

假设,ways[v]是用$x1$x2制作$v的方法, .. $xm,每个都可以根据需要多次使用。现在,如果我们只使用 n1$x1,我们必须使用至少 (n1 + 1) 个$x1 (实际上是 ways[v - (n1 + 1)x1] )。此外,如果我们只使用 n2$x2 个数,我们必须减去 ways[v - (n2 + 1) x2] 以及等等。

现在,我们已经两次减去至少 (n1 + 1) $x1 和 (n2 + 1) $x2 被使用,因此我们需要添加 ways[v -(n1 + 1)x1 - (n2 + 1)x2] 等。

特别是,如果,

N = 尽可能多地使用所有硬币的一组配置,

Ai = 一组配置,其中至少使用了 ni + 1 个 $xi,对于 1 i m,然后

我们正在寻找的结果 = |N| - |A1| - |A2| .. - || + |A1A2| + |A1A3| + ... - |A1A2A3| .....

计算无限硬币配置数量的代码实际上更简单:

ways[0]=1;
for( int i = 0 ; i < count ; i++){
    for( int j = coins[i] ; j < ways.size() ; j++ ){
        ways[j] += ways[j-coins[i]];
    }
}

【问题讨论】:

    标签: c algorithm dynamic-programming knapsack-problem coin-change


    【解决方案1】:

    假设你所有的ni 都是1

    ways[j] = number of ways of obtaining sum j.

    你可以这样计算(这就是你正在做的,但我不知道你为什么将你的变量命名为primes)。

    ways[0] = 1
    for i = 1 to m do
        for j = myLim downto X[i] do
            ways[j] += ways[j - X[i]];
    

    这意味着您只使用价值Xi 的每个硬币一次。您可以添加另一个循环来使用它至少一次,最多 ni 次:

    ways[0] = 1
    for i = 1 to m do
        for times = 1 to n[i] do // use Xi one time, then two times, then three, ..., then ni
            for j = myLim downto times*X[i] do
                ways[j] += ways[j - times*X[i]];
    

    你仍然可以应用你的模数并计算你的极限,为了简单起见,我把它们省略了。

    【讨论】:

    • 嗯,使用素数很容易解释原因。我从一个要求质值硬币的代码中复制了它。 :P。并且使用“时间”无济于事......我想我就是这样做的,但它以比平时更大的答案结束。 MAs MathWorld 说,需要 GCD.... 我正在尝试扩展这个想法。非常感谢您的回答:)。
    • 您能否进一步解释这个答案?我遇到了硬币找零问题,但在硬币有限时遇到了麻烦,例如1p = 6 个硬币,2p = 10 个硬币等
    • 我相信 j 循环应该以递增的顺序填充,因为您正在查看以前的方式[j]。我说的对吗?
    • @marti 否,因为那样的话,在同一次迭代中,您将使用已经计算的值,可能使用Xi 的次数超过了允许的次数。
    【解决方案2】:

    这个问题被命名为“硬币问题”并且已知是 NP-hard。

    你可以了解一下here.

    【讨论】:

    • 我看不出这有什么关系。 OP的问题没有提到GCD并要求不同的东西。
    • @IVlad 他还说一个朋友告诉我这是背包问题的变种,但我不确定,如何。这个问题有一个名字,并且一直是学了很多。这不是玩具问题。
    • 可能是这样,但绝对不是您链接的内容。
    • @IVlad 我认为是。如果 GCD 大于 1,则有更多的解决方案,您可以通过使用 sub-multiples 轻松获得。 (即用两个 5 美元硬币代替 10 美元硬币)。但你必须首先解决难题。只需移除非 GCD=1 的硬币,解决问题,然后添加那些您可以填充更高面额的组合(非 GCD =1)
    • 链接的问题似乎是关于largest nonrepresentable amounts - 我没有连接到how many ways can we obtain $X。 (它提到了No closed-form solution is known [generally],再加上您上面的known to be NP-hard,我问:您是否在考虑正确的问题,但提供了指向(松散)相关但不同的问题的链接?)
    猜你喜欢
    • 2017-10-28
    • 2019-07-17
    • 2016-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-04
    • 2014-01-11
    • 1970-01-01
    相关资源
    最近更新 更多