hdu 2191 多重背包 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活
http://acm.hdu.edu.cn/showproblem.php?pid=2191
悼念512汶川大地震遇难同胞——珍惜现在,感恩生活Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 17930 Accepted Submission(s): 7555 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
Source
Recommend
|
建议自己用这种解法:
1 #include <iostream> 2 #include<cstdio> 3 #include<string.h> 4 using namespace std; 5 6 /* 多重背包 二进制拆分 7 * Time Complexity 大于O(N*V) 8 * Space Complexity O(N*V) 9 * 设 V <= 200 N <= 10 ,拆分后 物品总数 < 50 10 * 每件物品有 log n[i]种状态 11 */ 12 13 int maxV[721]; 14 int weight[1520]; /* 记录拆分后物体重量 */ 15 int value[1520]; /* 记录拆分后物体价值 */ 16 int V, N; 17 18 int main() 19 { 20 int _case; 21 scanf("%d",&_case); 22 while(_case--){ 23 int i, j; 24 scanf("%d%d",&V, &N); 25 int weig, val, num; 26 int count = 0; 27 28 for(i = 0; i < N; ++i) 29 { 30 scanf("%d%d%d",&weig,&val,&num); 31 32 for(j = 1; j <= num; j*=2) // 二进制拆分 33 { 34 weight[count] = j * weig; 35 value[count++] = j * val; 36 num -= j; 37 } 38 if(num > 0) 39 { 40 weight[count] = num * weig; 41 value[count++] = num * val; 42 } 43 } 44 45 46 memset(maxV,0,sizeof(maxV)); 47 for(i = 0; i < count; ++i) // 使用01背包 48 { 49 for(j = V; j >= weight[i]; --j) 50 { 51 int tmp = maxV[j-weight[i]] + value[i]; 52 maxV[j] = maxV[j] > tmp ? maxV[j] : tmp; 53 } 54 } 55 printf("%d\n",maxV[V]);} 56 return 0;}
1 #include<stdio.h> 2 #include<string.h> 3 int dp[101];//dp[j]表示钱为j时能买的最大重量 4 struct Node 5 { 6 int p;//价格 7 int w;//重量 8 int c;//数量 9 }s[102]; 10 int main() 11 { 12 int t,N,m; 13 int i,j,k,temp; 14 scanf("%d",&t); 15 while(t--) 16 { 17 memset(dp,0,sizeof(dp)); 18 scanf("%d%d",&N,&m); 19 for(i=1;i<=m;i++) 20 scanf("%d%d%d",&s[i].p,&s[i].w,&s[i].c); 21 for(j=0;j<s[1].p;j++) 22 dp[j] = 0; 23 for(;j<=N;j++) 24 { 25 temp = j/s[1].p; 26 if(temp <= s[1].c) 27 dp[j] = temp * s[1].w; 28 else 29 dp[j] = s[1].c * s[1].w; 30 } 31 32 for(i=2;i<=m;i++)//米的种类 33 { 34 for(j=N;j>=s[i].p;j--)//钱的数量 35 { 36 for(k = 0;k<=s[i].c;k++)//米的代数 37 { 38 temp = k * s[i].p; 39 if(temp <= j ) 40 { 41 if(dp[j-temp]+k*s[i].w > dp[j]) 42 dp[j] = dp[j-temp]+k*s[i].w; 43 } 44 else 45 break; 46 } 47 } 48 } 49 printf("%d\n",dp[N]); 50 } 51 return 0; 52 }
二进制拆分:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 const int N=110; 5 using namespace std; 6 int n,m; 7 8 struct Rice{ 9 int price; 10 int weight; 11 int number; 12 }rice[N]; 13 int dp[N]; 14 //完全背包 15 void CompletePack(int cost,int weight){ 16 for(int i=cost;i<=n;i++){ 17 dp[i]=max(dp[i],dp[i-cost]+weight); 18 } 19 } 20 //01背包 21 void ZeroOnePack(int cost,int weight){ 22 for(int i=n;i-cost>=0;i--){ 23 dp[i]=max(dp[i],dp[i-cost]+weight); 24 } 25 } 26 27 //多重背包 28 void MultiplePack(int cost,int weight,int number){ 29 //如果大于等于金额,就按完全背包处理(此时相当于不限定袋数)//我试过,不用完全背包也可以 30 if(cost*number>=n){ 31 CompletePack(cost,weight); 32 return ; 33 } 34 int k=1; 35 while(k<number){ 36 ZeroOnePack(k*cost,k*weight); 37 number-=k; 38 k*=2; 39 } 40 ZeroOnePack(number*cost,number*weight); 41 } 42 43 int main(){ 44 int _case; 45 scanf("%d",&_case); 46 while(_case--){ 47 scanf("%d%d",&n,&m); 48 memset(dp,0,sizeof(dp)); 49 for(int i=0;i<m;i++){ 50 scanf("%d%d%d",&rice[i].price,&rice[i].weight,&rice[i].number); 51 } 52 for(int i=0;i<m;i++){ 53 MultiplePack(rice[i].price,rice[i].weight,rice[i].number); 54 } 55 printf("%d\n",dp[n]); 56 } 57 return 0; 58 }