ZOJ3164【背包问题(好题)】

来源:互联网 发布:java用两个栈实现队列 编辑:程序博客网 时间:2024/05/20 00:38

%%%%%%%%%%%%%%%岐爷

这一发从来没写过这么旺盛的背包问题。。。

想法很多,但是好难执行。

题意:
有N种饼干,1-N
每种最多想买Ki个,ki等于0的话没有上界
对于第i种饼干的权值是Ei
第i种饼干的价格Pi
有D钱。

还有G组

每组只能选一种。

思路:
有两种背包,一种是在一定的组里,还有没有特定关系;
没有特定关系的,如果没有限定数或者限定数*花费大于总费用,直接完全背包;否则就是二进制优化的0/1背包;
有特定关系的就是一个分组背包,先预处理第i组j花费下的最优情况,且初始化每组每个花费下的价值都是-INF,然后最后dp,之前还要预处理一种物品在j花费下所能达到的最优值;
最后dp将每一个分组的价格当做一次01背包 ,最里面再for一层。

#include<bits/stdc++.h>using namespace std;const int N=1e3+50;const int INF=0x3f3f3f3f;int n,W;void zero_one(int dp[],int w,int val){    for(int i=W;i>=w;i--)        if(dp[i-w]>-INF)            dp[i]=max(dp[i],dp[i-w]+val);}void compelet(int dp[],int w,int val){    for(int i=w;i<=W;i++)        if(dp[i-w]>-INF)            dp[i]=max(dp[i],dp[i-w]+val);}void init(int dp[]){    fill(dp,dp+W+1,-INF);    dp[0]=0;}int Kkk[N],Eee[N],Ppp[N];int mp[N];int dp[N],temp[N];char s[N];int w[10][N];int main(){    while(~scanf("%d%d",&n,&W))    {        for(int i=1; i<=n; i++)            scanf("%d%d%d",&Kkk[i],&Eee[i],&Ppp[i]);        int G,len;        scanf("%d",&G);        getchar();        memset(mp,0,sizeof(mp));        for(int i=1; i<=G; i++)        {            gets(s);            len=strlen(s);            for(int j=0; j<len;)            {                if(s[j]>='1'&&s[j]<='9')                {                    int sum=0;                    while(s[j]>='0' && s[j] <= '9')                    {                        sum=sum*10+s[j]-'0';                        j++;                    }                    mp[sum]=i;                }                else                    j++;            }        }        int k,ww,ept;                init(dp);        for(int i=1;i<=G;i++)            init(w[i]);                for(int i=1; i<=n; i++)        {            if(mp[i])                init(temp);            if(!Kkk[i]||Kkk[i]*Ppp[i]>=W)            {                compelet(mp[i]?temp:dp,Ppp[i],Eee[i]);            }            else            {                k=1;                while(k<=Kkk[i])                {                    ww=k*Ppp[i];                    ept=k*Eee[i];                    zero_one(mp[i]?temp:dp,ww,ept);                    Kkk[i]-=k;                    k<<=1;                }                ww=Kkk[i]*Ppp[i];                ept=Kkk[i]*Eee[i];                zero_one(mp[i]?temp:dp,ww,ept);            }            if(mp[i])                for(int j=0;j<=W;j++)                    w[mp[i]][j]=max(w[mp[i]][j],temp[j]); //预处理ww代表某一组里占花费j的最大收获        }        for(int i=1;i<=G;i++)            for(int j=W;j>=0;j--)                for(int k=0;k<=j;k++)                        if(dp[j-k]>-INF&&w[i][k]>-INF)                            dp[j]=max(dp[j],dp[j-k]+w[i][k]);        if(dp[W]>=0)            printf("%d\n",dp[W]);        else            puts("i'm sorry...");        puts("");    }    return 0;}/*2 10240 1 30 0 1010 10231 1 11 1 21 1 41 1 81 1 161 1 321 1 641 1 1283 -1 2561 1 51219 1010 10231 1 11 1 21 1 41 1 81 1 161 1 321 1 641 1 1281 1 2561 1 51219 10*/


0 0
原创粉丝点击