我已经编写了一个用于生成子集求和的程序,该程序可能会在这个问题中使用:
假设您有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]];
}
}
答案 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.