多重背包 - 二进制优化
分析:
每个数都可以用比它小的二进制数来表示,且每个数不重复使用 例如: 7 = 4 + 2 + 1; 9 = 8 + 1; 14 = 8 + 4 + 2 ..... // 1 2 4 8 16 32 64
然后就可以把给定的物品种数,分解成数量较小的多种物品,但是物品都是一样的,不影响后续01背包操作。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #define LL long long 5 using namespace std; 6 7 int n, w, v, s, h; //n为物品种类 w为背包容量 v为价值 s为体积 h为数量 8 int cnt; //cnt为重新分组过后的总种类数 9 int value[800], size[800]; 10 int dp[50005]; 11 int main() 12 { 13 memset(dp,0,sizeof(dp)); 14 cin >> n >> w; 15 for(int i = 0; i < n; i++){ 16 cin >> s >> v >> h; 17 for(int j = 1; j <= h; j <<= 1){ //j*=2; 18 value[cnt] = j*v; 19 size[cnt++] = j*s; 20 h -= j; 21 } 22 if(h > 0){ 23 value[cnt] = h*v; 24 size[cnt++] = h*s; 25 } 26 } 27 for(int i = 0; i < cnt; i++) 28 for(int j = w; j >= size[i]; j--) 29 dp[j] = max(dp[j],dp[j-size[i]]+value[i]); 30 cout << dp[w] << endl; 31 return 0; 32 }
注意点:
- value数组和size数组要开大些! 具体看题目,因为重新分组过后,种类会变多,不止原来的n种
-
1 for(int i = 0; i < n; i++){ 2 cin >> s >> v >> h; 3 for(int j = 1; j <= h; j <<= 1){ //j*=2; 4 value[cnt] = j*v; 5 size[cnt++] = j*s; 6 h -= j; 7 } 8 if(h > 0){ 9 value[cnt] = h*v; 10 size[cnt++] = h*s; 11 } 12 }
二进制处理,不要忘了每处理一次后余下的h!! 比如,100 = 1 + 2 + 4 + 8 + 16 + 32 + 37; (37就放在if(h > 0)处理)
- 后续的01背包的第一重循环的 n 要换成 cnt, 也不能忘。
好吧,好像都是我忘了的点,后来才恍然大悟的! 要细心呀!! 细心
总的来看,优化也不算难,理解就很简单。 可是,我自己看博客看了半天还是懵的,还是ff讲的比较好理解~ 哎呀哎呀 哈哈哈哈哈
好啦,就到这里啦! over!
对了对了,放个题,51nod 1086背包问题 V2
代码就是上面的模板!
白白 ヾ(•ω•`)o