首先,什么叫多重背包呢?

大概意思就是:一个背包有V总容量,有N种物品,其价值分别为Val1,Val2……,Val3,体积对应的是Vol1,Vol2,……,Vol3,件数对应Num1,Num2……,Num3

求背包至多装满的最大总价值。

其实,首先可以当作01背包来做,这时候复杂度就是O(V*sum(Num[i]));

简单代码来说就是

  1. for(int i=1;i<=N;i++)
  2. for(int j=1;j<=Num[i];j++)
  3. for(int k=V;k>=Vol[i];k++)
  4. dp[k]=max(dp[k],dp[k-Vol[i]]+Val[i]);

很容易超时。如果M大的话。从大神的背包九讲看到一个化成O(Vsum(log(Num[i])))

大概意思就是利用先判断是否为完全背包情况,否则二进制压缩进行01背包的步骤。任何一个数目Num[i],可以表示为1+2^1 +……+2^p+Num[i]-2^(p+1)+1 其中确定p的条件是Num[i]-2^(p+1)+1>0,Num[i]-2^(p+2)+1<0

这样我们就可以将第i件物品化成 logNum[i]件物品,起对应的容量和价值,分别对应相应倍数

简单代码就是

  1. int i,j,k;
  2. for(i=1; i<=N; i++)
  3. if(Vol[i]*Num[i]>=V) //n*v>=V 完全背包
  4. {
  5. for(j=Vol[i]; j<=V; j++) //从val到V
  6. {
  7. dp[j]=max(dp[j],dp[j-Vol[i]]+Val[i]);
  8. }
  9.  
  10. }
  11. else
  12. {
  13. k=1;
  14. int num_tmp=Num[i]; //取出数目
  15. while(k<num_tmp) //二进制优化
  16. {
  17. for(j=V; j>=k*Vol[i]; j--) //k*Vol ,k*Val的背包
  18. dp[j]=max(dp[j],dp[j-k*Vol[i]]+Val[i]);
  19. num_tmp-=k;
  20. k<<=1;
  21. }
  22. for(j=V; j>=num_tmp*vol[i]; j--) //num_tmp*Vol[i],num_tmp*Val[i]背包问题
  23. {
  24. dp[j]=max(dp[j],dp[j-num_tmp*Vol[i] ]+Val[i]);
  25. }
  26.  
  27. }

之后对于HDU1171,2194,用第一种算法就轻松通过了。

HDU1171的题目要我们做的就是将总和/2规划成资产“不会大”的学院当成容量背包。

代码

  1. #include<stdio.h>
  2. #include<string.h>
  3. int dp[250000];
  4. int val[52];
  5. int num[52];
  6. int main(){
  7.  
  8. int n,i,j,k;
  9. int sum,V;
  10. while(scanf("%d",&n)&&n>0){
  11.  
  12. memset(dp,0,sizeof(dp));
  13.  
  14. sum=0;
  15. for(i=1;i<=n;i++){
  16. scanf("%d%d",&val[i],&num[i]);
  17. sum+=val[i]*num[i];
  18. }
  19. V=sum/2; //B的
  20. for(i=1;i<=n;i++){
  21. for(j=1;j<=num[i];j++){
  22. for(k=V;k>=val[i];k--){
  23. dp[k]=dp[k]>dp[k-val[i]]+val[i]?dp[k]:dp[k-val[i]]+val[i];
  24.  
  25. }
  26.  
  27. }
  28.  
  29. }
  30. printf("%d %d\n",sum-dp[V],dp[V]);
  31.  
  32. }
  33.  
  34. return 0;
  35.  
  36. }

而HDU2191则是赤裸裸的套上模版,更是轻松过。不过在取数组名字时候真是乱七八糟。我有时候用cost val num,有时候用vol val num不过关系都不大。

  1. #include<stdio.h>
  2. #include<string.h>
  3. int dp[106];
  4. int cst[100];
  5. int val[100];
  6. int num[100];
  7. int max(int a,int b){
  8. return a>b?a:b;
  9.  
  10. }
  11. int main(){
  12.  
  13. int cases,V,N,i,j,k;
  14. scanf("%d",&cases);
  15. while(cases--){
  16. scanf("%d%d",&V,&N);
  17. memset(dp,0,sizeof(dp));
  18. memset(cst,0,sizeof(cst));
  19. memset(val,0,sizeof(val));
  20. memset(num,0,sizeof(num));
  21. for(i=1;i<=N;i++)
  22. scanf("%d%d%d",&cst[i],&val[i],&num[i]);
  23.  
  24. for(i=1;i<=N;i++)
  25. for(j=1;j<=num[i];j++)
  26. for(k=V;k>=cst[i];k--){
  27. dp[k]=max(dp[k],dp[k-cst[i]]+val[i]);
  28.  
  29. }
  30.  
  31. printf("%d\n",dp[V]);
  32.  
  33. }
  34. return 0;
  35.  
  36. }

对于HDU2844这题目,我错了很多次……大多数都是RE……后来大我AC了我才发现,是我当初的数组开的太小了。

大概思路就是:令vol=val,来做成背包,能付多少钱嘛,那么dp[i]==i就是刚好付i元,最后统计一下就好啦。

一开始我试着直接化成01背包,果断TLE了……

  1. /*******************************************************************************/
  2. /* OS : 3.2.0-58-generic #88-Ubuntu SMP Tue Dec 3 UTC 2013 GNU/Linux
  3. * Compiler : GCC 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
  4. * Encoding : UTF8
  5. * Date : 2014-03-11
  6. * All Rights Reserved by yaolong.
  7. *****************************************************************************/
  8. /* Description: ***************************************************************
  9. *****************************************************************************/
  10. /* Analysis: ******************************************************************
  11. *****************************************************************************/
  12. /*****************************************************************************/
  13.  
  14. #include<stdio.h>
  15. #include<string.h>
  16. int dp[100002];
  17. int val[122];
  18. int num[122];
  19. int max(int a,int b)
  20. {
  21. return a>b?a:b;
  22.  
  23. }
  24. int main()
  25. {
  26.  
  27. int V,N,i,j,res;
  28.  
  29. while(~scanf("%d%d",&N,&V)&&(N||V))
  30. {
  31.  
  32. memset(dp,0,sizeof(dp));
  33.  
  34. for(i=1; i<=N; i++)
  35. scanf("%d",&val[i]);
  36. for(i=1; i<=N; i++)
  37. scanf("%d",&num[i]);
  38.  
  39. for(i=1; i<=N; i++)
  40. {
  41. if(val[i]*num[i]>=V) //n*v>=V 完全背包
  42. {
  43. for(j=val[i]; j<=V; j++) //从val到V
  44. {
  45. dp[j]=max(dp[j],dp[j-val[i]]+val[i]);
  46. }
  47.  
  48. }
  49. else
  50. {
  51. int k=1;
  52. int num_tmp=num[i]; //取出数目
  53. while(k<num_tmp) //二进制优化
  54. {
  55. for(j=V; j>=k*val[i]; j--) //k*val ,k*val的背包
  56. dp[j]=max(dp[j],dp[j-k*val[i]]+k*val[i]);
  57. num_tmp-=k;
  58. k<<=1;
  59. }
  60. for(j=V; j>=num_tmp*val[i]; j--) //num_tmp*val[i],num_tmp*val[i]背包问题
  61. {
  62. dp[j]=max(dp[j],dp[j-num_tmp*val[i]]+num_tmp*val[i]);
  63. }
  64.  
  65. }
  66.  
  67. }
  68.  
  69. res=0;
  70.  
  71. for(i = 1; i<=V; i++)
  72.  
  73. if(dp[i]==i)
  74. {
  75. res++;
  76. }
  77.  
  78. printf("%d\n",res);
  79.  
  80. }
  81.  
  82. return 0;
  83.  
  84. }

后来我又写了一遍,因为我当初把各种背包函数写在外面出错了,其实我一直不明白为什么GCC提交,打注释就有问题……

  1. /*******************************************************************************/
  2. /* OS : 3.2.0-58-generic #88-Ubuntu SMP Tue Dec 3 UTC 2013 GNU/Linux
  3. * Compiler : GCC 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
  4. * Encoding : UTF8
  5. * Date : 2014-03-11
  6. * All Rights Reserved by yaolong.
  7. *****************************************************************************/
  8. /* Description: ***************************************************************
  9. *****************************************************************************/
  10. /* Analysis: ******************************************************************
  11. *****************************************************************************/
  12. /*****************************************************************************/
  13.  
  14. #include<stdio.h>
  15. #include<string.h>
  16. int dp[100002];
  17. int w[122]; //weight
  18. int n[122]; //num
  19. int v[122]; //volume
  20. int V,N;//Volume of the Pack,Number of things
  21.  
  22. int max(int a,int b)
  23. {
  24. return a>b?a:b;
  25.  
  26. }
  27. void ZeroOnePack(int vol,int weight){
  28. int i;
  29. for(i=V;i>=vol;i--){
  30. dp[i]=max(dp[i],dp[i-vol]+weight);
  31. }
  32.  
  33. }
  34. void CompletePack(int vol,int weight){
  35. int i;
  36. for(i=vol;i<=V;i++){
  37. dp[i]=max(dp[i],dp[i-vol]+weight);
  38. }
  39.  
  40. }
  41. void MultiPack(int vol,int weight,int num){
  42.  
  43. if(num*vol>=V){//CompletePack
  44. CompletePack(vol,weight);
  45. return ;
  46. }
  47. int k=1;
  48. while(k<num){
  49. ZeroOnePack(k*vol,k*weight); //ZeroOnePackage
  50. num-=k;
  51. k<<=1;
  52. }
  53. ZeroOnePack(num*vol,num*weight);
  54.  
  55. }
  56. int main()
  57. {
  58. int i,res;
  59. while(scanf("%d%d",&N,&V),N+V){
  60. memset(dp,0,sizeof(dp));
  61. for(i=1;i<=N;i++)
  62. scanf("%d",&w[i]);
  63. for(i=1;i<=N;i++)
  64. scanf("%d",&n[i]);
  65. for(i=1;i<=N;i++)
  66. MultiPack(w[i],w[i],n[i]);
  67.  
  68. res=0;
  69. for(i=1;i<=V;i++)
  70. if(dp[i]==i){
  71. res++;
  72. }
  73. printf("%d\n",res);
  74.  
  75. }
  76.  
  77. return 0;
  78.  
  79. }

多重背包的入门题目HDU1171,2191,2844.的更多相关文章

  1. POJ 1014 Dividing(多重背包)

    Dividing   Description Marsha and Bill own a collection of marbles. They want to split the collectio ...

  2. hdu 2191 珍惜现在,感恩生活 多重背包入门题

    背包九讲下载CSDN 背包九讲内容 多重背包: hdu 2191 珍惜现在,感恩生活 多重背包入门题 使用将多重背包转化为完全背包与01背包求解: 对于w*num>= V这时就是完全背包,完全背 ...

  3. hdu 2844 Coins (多重背包)

    题意是给你几个数,再给你这几个数的可以用的个数,然后随机找几个数来累加, 让我算可以累加得到的数的种数! 解题思路:先将背包初始化为-1,再用多重背包计算,最后检索,若bb[i]==i,则说明i这个数 ...

  4. Coins(HDU 2844):一个会超时的多重背包

    Coins  HDU 2844 不能用最基础的多重背包模板:会超时的!!! 之后看了二进制优化了的多重背包. 就是把多重转变成01背包: 具体思路见:http://www.cnblogs.com/tt ...

  5. hdu 2191 多重背包 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活

    http://acm.hdu.edu.cn/showproblem.php?pid=2191 New~ 欢迎“热爱编程”的高考少年——报考杭州电子科技大学计算机学院关于2015年杭电ACM暑期集训队的 ...

  6. [原]hdu2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 (这个只是题目名字) (多重背包)

    本文出自:http://blog.csdn.net/svitter 原题:http://acm.hdu.edu.cn/showproblem.php?pid=2191 题意:多重背包问题.转换成为01 ...

  7. HDU 2844 Coins(多重背包)

    点我看题目 题意 :Whuacmers有n种硬币,分别是面值为A1,A2,.....,An,每一种面值的硬币的数量分别是C1,C2,......,Cn,Whuacmers想买钱包,但是想给人家刚好的钱 ...

  8. HDu -2844 Coins多重背包

    这道题是典型的多重背包的题目,也是最基础的多重背包的题目 题目大意:给定n和m, 其中n为有多少中钱币, m为背包的容量,让你求出在1 - m 之间有多少种价钱的组合,由于这道题价值和重量相等,所以就 ...

  9. hdu 2191多重背包

    悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Jav ...

随机推荐

  1. CG&Game资源(转)

    cg教程下载: http://cgpeers.com http://cgpersia.com http://bbs.ideasr.com/forum-328-1.html http://bbs.ide ...

  2. HDOJ/HDU 1180 诡异的楼梯(经典BFS-详解)

    Problem Description Hogwarts正式开学以后,Harry发现在Hogwarts里,某些楼梯并不是静止不动的,相反,他们每隔一分钟就变动一次方向. 比如下面的例子里,一开始楼梯在 ...

  3. [CODEVS3641]上帝选人

    题目描述 Description 世界上的人都有智商IQ和情商EQ.我们用两个数字来表示人的智商和情商,数字大就代表其相应智商或情商高.现在你面前有N个人,这N个人的智商和情商均已知,请你选择出尽量多 ...

  4. codeforces Codeforces 650A Watchmen

    题意:两点(x1,y1), (x2,y2)的曼哈顿距离=欧几里得距离 也就是:x1=x2或y1=y2,再删除重合点造成的重复计数即可. #include <stdio.h> #includ ...

  5. 矩阵乘法 and BIOS loads MBR into 0x7C00?

    tianpeng <再谈矩阵与矩阵乘法> 讲的也好 矩阵乘矩阵 这个结果是怎么算出来的? 第一个矩阵第一行的每个数字(2和1),各自乘以第二个矩阵第一列对应位置的数字(1和1),然后将乘积 ...

  6. glance was not installed properly

  7. HighCharts 后台加载数据的时候去掉默认的 series

    var chart; var options = { chart: { renderTo: 'container', type:'line' }, title: { text: '历史趋势时序图', ...

  8. Android中应用程序如何获得系统签名权限

    有些库的使用条件比较苛刻,要求同一签名的程序才可以获得访问权.此时即便是在AndroidManifest.xml中添加了相应的permission,依旧会得到没有xx访问权限的问题.比如android ...

  9. mybatis08

    Mybatis解决jdbc编程的问题 .数据库链接创建.释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题. 解决:在SqlMapConfig.xml中配置数据链接池,使用连接 ...

  10. centos6.7 install chrome

    1.yum仓库 (如果用rpm包安装 可以忽略此步) vim /etc/yum.repos.d/google-chrome.repo [google-chrome] name=google-chrom ...