hdu 2191 (多重背包+二进制优化)

Problem Description
急!灾区的食物依然短缺!
为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。
请问:你用有限的资金最多能采购多少公斤粮食呢?

后记:
人生是一个充满了变数的生命过程,天灾、人祸、病痛是我们生命历程中不可预知的威胁。
月有阴晴圆缺,人有旦夕祸福,未来对于我们而言是一个未知数。那么,我们要做的就应该是珍惜现在,感恩生活——
感谢父母,他们给予我们生命,抚养我们成人;
感谢老师,他们授给我们知识,教我们做人
感谢朋友,他们让我们感受到世界的温暖;
感谢对手,他们令我们不断进取、努力。 
同样,我们也要感谢痛苦与艰辛带给我们的财富~

 

 

Input
输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。
 

 

Output
对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。
 

 

Sample Input
1
8 2
2 100 4
4 100 2
 

 

Sample Output
400
 

 

Author
lcy

 

比较直白的(数据较小):

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <memory.h>
 4 using namespace std;
 5 
 6 int c[105], w[105], n[105];
 7 int bag[105];
 8 int N, V;
 9 
10 void _mul_bag()     //多重背包:直接转换成01背包(数据比较小)
11 {
12     int i, j, k;
13     memset(bag, 0, sizeof(bag));
14     for(i = 0; i < N; i++)
15     {
16         for(k = 1; k <= n[i]; k++)
17         {
18             for(j = V; j >= c[i]; j--)
19             {
20                 bag[j] = max(bag[j], bag[j-c[i]] + w[i]);
21             }
22         }
23     }
24 }
25 
26 int main()
27 {
28     int i, t;
29     scanf("%d", &t);
30     while(t--)
31     {
32         scanf("%d %d", &V, &N);
33         for(i = 0; i < N; i++)
34             scanf("%d %d %d", &c[i], &w[i], &n[i]);
35         _mul_bag();
36         printf("%d\n", bag[V]);
37     }
38 
39     return 0;
40 }
View Code

 

 二进制优化:

 1 在这之前,我空间好像转过一个背包九讲,现在我就只对  
 2     01背包和多重背包有点印象了  
 3   
 4     先说下 01 背包,有n 种不同的物品,每个物品有两个属性  
 5     size 体积,value 价值,现在给一个容量为 w 的背包,问  
 6     最多可带走多少价值的物品。  
 7   
 8     int f[w+1];   //f[x] 表示背包容量为x 时的最大价值  
 9     for (int i=0; i<n; i++)  
10         for (int j=w; j>=size[i]; j++)  
11             f[j] = max(f[j], f[j-size[i]]+value[i]);  
12   
13     如果物品不计件数,就是每个物品不只一件的话,稍微改下即可  
14     for (int i=0; i<n; i++)  
15         for (int j=size[i]; j<=w; j++)  
16             f[j] = max(f[j], f[j-size[i]]+value[i]);  
17   
18     f[w] 即为所求  
19   
20     初始化分两种情况  
21     1、如果背包要求正好装满则初始化 f[0] = 0, f[1~w] = -INF;  
22     2、如果不需要正好装满 f[0~v] = 0;  
23   
24     多重背包问题要求很简单,就是每件物品给出确定的件数,求  
25     可得到的最大价值  
26   
27     多重背包转换成 01 背包问题就是多了个初始化,把它的件数C 用  
28     分解成若干个件数的集合,这里面数字可以组合成任意小于等于C  
29     的件数,而且不会重复,之所以叫二进制分解,是因为这样分解可  
30     以用数字的二进制形式来解释  
31     比如:7的二进制 7 = 111 它可以分解成 001 010 100 这三个数可以  
32     组合成任意小于等于7 的数,而且每种组合都会得到不同的数  
33 = 1111 可分解成 0001  0010  0100  1000 四个数字  
34     如果13 = 1101 则分解为 0001 0010 0100 0110 前三个数字可以组合成  
35     7以内任意一个数,加上 0110 = 6 可以组合成任意一个大于6 小于13  
36     的数,虽然有重复但总是能把 13 以内所有的数都考虑到了,基于这种  
37     思想去把多件物品转换为,多种一件物品,就可用01 背包求解了。  
38   
39   
40     看代码:  
41     int n;  //输入有多少种物品  
42     int c;  //每种物品有多少件  
43     int v;  //每种物品的价值  
44     int s;  //每种物品的尺寸  
45     int count = 0; //分解后可得到多少种物品  
46     int value[MAX]; //用来保存分解后的物品价值  
47     int size[MAX];  //用来保存分解后物品体积  
48   
49     scanf("%d", &n);    //先输入有多少种物品,接下来对每种物品进行分解  
50   
51     while (n--) {   //接下来输入n中这个物品  
52         scanf("%d%d%d", &c, &s, &v);  //输入每种物品的数目和价值  
53         for (int k=1; k<=c; k<<=1) { //<<右移 相当于乘二  
54             value[count] = k*v;  
55             size[count++] = k*s;  
56             c -= k;  
57         }  
58         if (c > 0) {  
59             value[count] = c*v;  
60             size[count++] = c*s;  
61         }  
62     }  
63   
64     现在用count 代替 n 就和01 背包问题完全一样了
View Code

 

背包九讲里面,他的实现方法和这个是不一样的,利用01背包和完全背包来配合实现的,下面是实现:

 1 /* 
 2 HDOJ 2191 
 3 多重背包用二进制转化的思想,进行优化 
 4 */  
 5   
 6 #include <iostream>  
 7 using namespace std;  
 8   
 9 int weight[110],Value[110],num[110];  
10 int f[1100];  
11 int limit;  
12   
13 inline void ZeroOnePack(int w,int v)  
14 {  
15     int j;  
16     for(j=limit;j>=w;j--)  
17     {  
18         if(f[j-w]+v > f[j])  
19             f[j]=f[j-w]+v;  
20     }  
21 }  
22   
23 inline void CompletePack(int w,int v)  
24 {  
25     int j;  
26     for(j=w;j<=limit;j++)  
27     {  
28         if(f[j-w]+v > f[j])  
29             f[j]=f[j-w]+v;  
30     }  
31 }  
32   
33 inline void MultiplePack(int w,int v,int amount)  
34 {  
35     if(amount * w >= limit)  
36     {  
37         CompletePack(w,v);  
38         return ;  
39     }  
40     for(int k=1;k<amount;k<<=1)  
41     {  
42         ZeroOnePack(k*w,k*v);  
43         amount -= k;  
44     }  
45     ZeroOnePack(amount*w,amount*v);  
46 }  
47   
48 int main()  
49 {  
50     int T,n;  
51     cin>>T;  
52     while(T--)  
53     {  
54         cin>>limit>>n;  
55           
56         for(int i=0;i<n;i++)  
57             cin>>weight[i]>>Value[i]>>num[i];  
58           
59         memset(f,0,sizeof(f));  
60           
61         for(i=0;i<n;i++)  
62             MultiplePack(weight[i],Value[i],num[i]);  
63           
64         cout<<f[limit]<<endl;  
65     }  
66     return 0;  
67 }
View Code
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 int t,v,n;
 6 int c[109],w[109],num[109],F[109];
 7 
 8 void zeroonebag(int cost,int weight){
 9      for(int i=v;i >= cost;i--) F[i]=max(F[i],F[i-cost]+weight);
10 }
11 
12 void completebag(int cost,int weight){
13      for(int i=cost;i <= v;i++) F[i]=max(F[i],F[i-cost]+weight);
14 }
15 
16 void multiplybag(int cost,int weight,int num){
17      if(cost*num >= v) completebag(cost,weight);
18      else{
19         int k=1,m=num;
20         while(k < m){
21             zeroonebag(k*cost,k*weight);
22             m-=k;
23             k*=2;
24         }
25         zeroonebag(m*cost,m*weight);
26      }
27 }
28 
29 int main(void){
30     scanf("%d",&t);
31     while(t--){
32         scanf("%d%d",&v,&n);
33         for(int i=0;i < n;i++) scanf("%d%d%d",&c[i],&w[i],&num[i]);
34         memset(F,0,sizeof(F));
35         for(int i=0;i < n;i++) multiplybag(c[i],w[i],num[i]);
36         printf("%d\n",F[v]);
37     }
38     return 0;
39 }
View Code

 

单调队列:http://www.cppblog.com/flyinghearts/archive/2010/09/01/125555.aspx 

 

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <math.h>
 5 #include <algorithm>
 6 #include <iostream>
 7 using namespace std;
 8 int dp[102];
 9 int p[102],h[102],c[102];
10 int n,m;
11 void comback(int v,int w)//经费,重量。完全背包;
12 {
13     for(int i=v; i<=n; i++)
14         if(dp[i]<dp[i-v]+w)
15             dp[i]=dp[i-v]+w;
16 }
17 void oneback(int v,int w)//经费,重量;01背包;
18 {
19     for(int i=n; i>=v; i--)
20         if(dp[i]<dp[i-v]+w)
21             dp[i]=dp[i-v]+w;
22 }
23 int main()
24 {
25     int ncase,i,j,k;
26     scanf("%d",&ncase);
27     while(ncase--)
28     {
29         memset(dp,0,sizeof(dp));
30         scanf("%d%d",&n,&m);//经费,种类;
31         for(i=1; i<=m; i++)
32         {
33             scanf("%d%d%d",&p[i],&h[i],&c[i]);//价值,重量,数量;
34             if(p[i]*c[i]>=n) comback(p[i],h[i]);
35             else
36             {
37                 for(j=1; j<c[i]; j=j*2)
38                 {
39                     oneback(j*p[i],j*h[i]);
40                     c[i]=c[i]-j;
41                 }
42                 oneback(p[i]*c[i],h[i]*c[i]);
43             }
44         }
45         printf("%d\n",dp[n]);
46     }
47     return 0;
48 }

 

posted @ 2015-09-24 16:20  Vmetrio  阅读(245)  评论(0编辑  收藏  举报