【NEUOJ1907】有限制的背包问题
原题链接:多重背包
题意:将N种物品放入最大容量为W的背包中,其中每一种物品的价值为vi,体积为wi,数量为ci,问该背包所能装下的最大价值为多少。
思路:经典的多重背包问题,由于ci的数据范围较大,所以正常使用多重循环将多重背包改为有 n*ci 个物品的01背包问题会超时。此时我们需要一种巧妙的方法来优化拆分的思路,由于自然数范围内所有的数都可以用二进制来表示,所以我们可以将 \(c_i\) 拆分为 \(1 + 2 + 4 + 8 + ... + x\) 的形式,这种拆分方式可以在拆完后用拆分出的数表示\([1 , c_i]\)中所有的数。
具体拆分思路请看如下样例:
当我们试图将5拆分成二进制表示时,应当将其拆分为1,2,2,
再例如说我们试图拆分1000时,应将其拆分为1,2,4,8,16,32,64,128,256,489。
在了解完二进制的拆分思路后,外层循环从 n*ci 被优化为了 nlogn ,此时该题便迎刃而解了。
代码如下:
点击查看代码
for(int i = 0; i < n; i++) {
//二进制拆分方式
for(int j = 1; j <= c[i]; j *= 2) {
c[i] -= j;
int ww = w[i] * j, vv = v[i] * j;
for(int k = W; k >= ww; k--)
dp[k] = max(dp[k], dp[k - ww] + vv);
}
//可能会多出来一部分,也要算进去
if(c[i]) {
int ww = w[i] * c[i], vv = v[i] * c[i];
for(int k = W; k >= ww; k--)
dp[k] = max(dp[k], dp[k - ww] + vv);
}
}

浙公网安备 33010602011771号