多重背包 - 二进制优化

分析:                                                                                                                     

  每个数都可以用比它小的二进制数来表示,且每个数不重复使用   例如: 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 

 

posted @ 2018-08-12 21:56  愉也  阅读(175)  评论(0编辑  收藏  举报