【发布时间】: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| .. - |我| + |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]];
}
}
【问题讨论】:
标签: c algorithm dynamic-programming knapsack-problem coin-change