%%%%%%%%%%%%%%%岐爷
这一发从来没写过这么旺盛的背包问题。。。
想法很多,但是好难执行。
题意:
有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 ",dp[W]); else puts("i'm sorry..."); puts(""); } return 0; } /* 2 1024 0 1 3 0 0 1 0 10 1023 1 1 1 1 1 2 1 1 4 1 1 8 1 1 16 1 1 32 1 1 64 1 1 128 3 -1 256 1 1 512 1 9 10 10 1023 1 1 1 1 1 2 1 1 4 1 1 8 1 1 16 1 1 32 1 1 64 1 1 128 1 1 256 1 1 512 1 9 10 */