用有限数量的硬币更换硬币

时间:2010-11-16 19:37:29

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

我已经编写了一个用于生成子集求和的程序,该程序可能会在这个问题中使用:

  

假设您有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},然后对它运行Subset求和,当然我们可以得到$ 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;
    }
}

如果你能够精心解释一下,那对我来说会很棒。

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

这个问题可以通过包含排除原则来解决,当我们确定硬币值但每个硬币的数量随每个查询而变化时,它会很方便

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

现在,我们已经两次减去配置,其中至少( n1 + 1) $ x1 和( n2 + 1) $ x2 ,因此我们需要添加方式 [ v - (n1 + 1)x1 - (n2 + 1)x2 ]等。

特别是,如果,

N =所有硬币使用尽可能多的配置集

Ai =一组配置,其中至少使用 ni + 1个 $ xi 的数字,1&lt; = &lt; = m ,然后

我们正在寻找的结果= | N | - | A1 | - | A2 | .. - | 上午 | + | A1 A2 | + | A1 A3 | + ... - | A1 A2 A3 | .....

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

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]];
    }
}

2 个答案:

答案 0 :(得分:4)

我们假设您的所有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]];

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

答案 1 :(得分:-2)

问题被称为“硬币问题”,并且已知是NP难的。

您可以稍微了解一下here.