HDU 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活(多重背包,经典入门题)

来源:互联网 发布:行而知天下 编辑:程序博客网 时间:2024/06/05 10:49

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2191

题意:

C组测试数据

每组输入n,m,n:总经费  m:大米种类

输入每种大米的价格,重量,袋数(即库存)

问:最多能买多少大米(输出重量)


解题思路:

将多重背包转化为01背包,就是假设每一种米都只有一袋,那结果就只有两种:取或不取

很明显,直接可以用01背包解决

#include <cstdio>#include <cstring>#include <string>#include <iostream>#include <algorithm>using namespace std;struct node{int v,w;}p[2005];int ans[105];int main(){int t;scanf("%d",&t);while(t--){int n,m,pi,h,c,l=0;memset(p,0,sizeof(p));memset(ans,0,sizeof(ans));scanf("%d%d",&n,&m);for(int i=0;i<m;i++){scanf("%d%d%d",&pi,&h,&c);while(c--){p[l].v=pi;p[l].w=h;l++;}}for(int i=0;i<l;i++){for(int j=n;j>=p[i].v;j--){ans[j] = max(ans[j],ans[j-p[i].v]+p[i].w);}}printf("%d\n",ans[n]);}return 0;}



然而,当数据特别大时,用这种方法会超时

可以用二进制的那种多重背包

二进制的多重背包实际上也还是转化为01背包和完全背包,只不过用了二进制,大大缩短了时间

首先要弄明白一点:

对于一个数n来说,他可以被拆成  n = a1*2^0+a2*2^1+a3*2^2.....+ak*2^(k-1)+res

 =a  +  b  +  c  +d  +  ....  +  e  +  res  

其中a1,a2,a3……的值是0,1,res是剩余的不能转化为2的k次方的数

这样表示的好处就是,可以用a  b  c  d  e  res表示n以内的任意数

比如n=13,n = 1+2+4+6

1 = 1

2 = 2

3 = 1+2

4 = 4

5 = 1+4

6 = 2+4

7 = 1+6等等

多重背包总会涉及到一个数量的问题,同样的,我们可以将数量用2的k次方表示

回归本题

对每一种米都枚举过去

如果这种米的 数量x单价>n,就说明拥有经费n时,想买这种米与它的数量无关,可以用完全背包,因为即使花掉所有的经费,你也不能买下这种所有的米

否则就用01背包


#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <string>using namespace std;#define N 105int n,m;struct Rice{    int price;    int weight;    int number;}rice[N];int dp[N]; void CompletePack(int cost,int weight)//完全背包{    for(int i=cost;i<=n;i++){        dp[i]=max(dp[i],dp[i-cost]+weight);    }}void ZeroOnePack(int cost,int weight)//01背包{    for(int i=n;i-cost>=0;i--){        dp[i]=max(dp[i],dp[i-cost]+weight);    }}void MultiplePack(int cost,int weight,int number)//多重背包{    //如果大于等于金额,就按完全背包处理(此时相当于不限定袋数)    if(cost*number>=n){        CompletePack(cost,weight);        return ;    }    int k=1;    while(k<number){        ZeroOnePack(k*cost,k*weight);//注意要*k         number-=k;        k*=2;    }    ZeroOnePack(number*cost,number*weight);}int main(){    int _case;    scanf("%d",&_case);    while(_case--){        scanf("%d%d",&n,&m);        memset(dp,0,sizeof(dp));        for(int i=0;i<m;i++){            scanf("%d%d%d",&rice[i].price,&rice[i].weight,&rice[i].number);        }        for(int i=0;i<m;i++){            MultiplePack(rice[i].price,rice[i].weight,rice[i].number);        }        printf("%d\n",dp[n]);    }    return 0;}



0 0
原创粉丝点击