洛谷 P1064 金明的预算方案
先把主件拆开。例如两个附件的物品,拆成只买主件、主+附1、主+附2、主+附1+附2这四种对于这个物品的选法。
然后跑类似普通背包的,ans[i][j]表示前i个物品用j的钱的最大收益。如果当前物品为附件则ans[i]直接从ans[i-1]复制,直接忽略当前物品。否则枚举当前物品的所有选法,ans[i][j]=max(ans[i-1][j],ans[i-1][j-v[i]]+val[i])更新。此处v[i]表示当前枚举到的对于当前物品的选法的总费用,val[i]表示当前枚举到的对于当前物品的选法的总价值。
错误记录(调至少半小时):
1.在当前物品为附件时,直接跳掉了,没有复制ans[i-1]的答案
2.在拆开物品的时候,某一行的v2[i]的push_back的元素中却出现了cost[...]
3.57行直接max(ans[i-1][k],ans[i-1][k-c2[i][j]]+v2[i][j]),把前面选法得到的好的答案丢了
1 #include<cstdio> 2 #include<algorithm> 3 #include<vector> 4 using namespace std; 5 int cost[70],val[70],q[70]; 6 vector<int> c2[70],v2[70],s[70]; 7 int ans[62][32100]; 8 int n,m; 9 int main() 10 { 11 int i,sz,j,k; 12 scanf("%d%d",&n,&m); 13 for(i=1;i<=m;i++) 14 { 15 scanf("%d%d%d",&cost[i],&val[i],&q[i]); 16 val[i]=val[i]*cost[i]; 17 if(q[i]!=0) s[q[i]].push_back(i); 18 } 19 for(i=1;i<=m;i++) 20 if(q[i]==0) 21 { 22 sz=s[i].size(); 23 if(sz==0) 24 { 25 c2[i].push_back(cost[i]); 26 v2[i].push_back(val[i]); 27 } 28 else if(sz==1) 29 { 30 c2[i].push_back(cost[i]); 31 v2[i].push_back(val[i]); 32 c2[i].push_back(cost[i]+cost[s[i][0]]); 33 v2[i].push_back(val[i]+val[s[i][0]]); 34 } 35 else if(sz==2) 36 { 37 c2[i].push_back(cost[i]); 38 v2[i].push_back(val[i]); 39 c2[i].push_back(cost[i]+cost[s[i][0]]); 40 v2[i].push_back(val[i]+val[s[i][0]]); 41 c2[i].push_back(cost[i]+cost[s[i][1]]); 42 v2[i].push_back(val[i]+val[s[i][1]]); 43 c2[i].push_back(cost[i]+cost[s[i][0]]+cost[s[i][1]]); 44 v2[i].push_back(val[i]+val[s[i][0]]+val[s[i][1]]); 45 } 46 } 47 // for(i=1;i<=m;i++) 48 // { 49 // for(int j=0;j<c2[i].size();j++) printf("%d %d ",c2[i][j],v2[i][j]); 50 // puts(""); 51 // } 52 for(i=1;i<=m;i++) 53 { 54 for(j=0;j<c2[i].size();j++) 55 { 56 for(k=c2[i][j];k<=n;k++) 57 ans[i][k]=max(ans[i][k],max(ans[i-1][k],ans[i-1][k-c2[i][j]]+v2[i][j])); 58 } 59 for(k=0;k<=n;k++) 60 ans[i][k]=max(ans[i][k],ans[i-1][k]); 61 } 62 printf("%d",*max_element(ans[m]+1,ans[m]+n+1)); 63 return 0; 64 }