背景:1——TL按照背包九讲的把没一个依赖组转用01背包转化成物品集合,然后又用分组背包的方法来做,超时。优化无果,借鉴别人思路ac。
正确写法思路:先不管必须选盒子这个前提,按照01背包的思想把物品选一次到thing[]数组中,然后再把再强项对每个数据都买盒子,这样thing中只有thing[Box....v]能买起盒子,且thing[k]=thing[k-Box]+0 ,盒子的价值是0.所以转移方程:F[j]=max{F[j],thing[k-Box]} (F[j]表示不选盒子和盒子里的物品的价值,thing[k-Box]表示选择盒子和盒子内的物品所能达到的最大价值)
题目注解见代码:
#include <iostream> #include<cstdio> #include<cstring> #define INF 100009 using namespace std; int thing[INF],F[INF]; int n,v,Box,mi,co[20],wo[20],sum_Box; int main(void){ while(~scanf("%d%d",&n,&v)){ memset(F,sizeof(F)); for(int i=0;i < n;i++){ scanf("%d%d",&Box,&mi); for(int j=0;j < mi;j++){ scanf("%d%d",&co[j],&wo[j]); } memcpy(thing,F,sizeof(F)); //继承上次的状态。 for(int i=0;i < mi;i++){ //在不考虑选择盒子的情况下,01背包式自由选择附件。 for(int j=v;j >= co[i];j--){ thing[j]=max(thing[j],thing[j-co[i]]+wo[i]); } } for(int i=0;i <= v;i++) F[i]=max(F[i],thing[i-Box]); /*减去盒子费用的转移:这里其实是把,自由选择下的F[Box...v],当做选了盒子之后的F[1...v-Box] } 这样就能满足:先必须选择一个盒子,再选择用01背包的方式选择一个物品的条件了*/ printf("%d\n",F[v]); } return 0; }
将附件集合转化为物品组的超时代码:
#include <iostream> #include<cstdio> #include<cstring> #define INF 100009 using namespace std; int thing[INF],sum_Box; void zeroonebag(void){ for(int j=0;j < mi;j++){ for(int k=sum_Box;k >= co[j];k--){ thing[k]=max(thing[k],thing[k-co[j]]+wo[j]); } } } int main(void){ while(~scanf("%d%d",&mi); sum_Box=0; for(int j=0;j < mi;j++){ scanf("%d%d",&wo[j]); sum_Box+=co[j]; } sum_Box=min(v-Box,sum_Box); memset(thing,sizeof(thing)); if(Box >= v) continue; zeroonebag(); //用01背包将附件集合转化为物品组。 for(int j=v;j >= 1;j--){ for(int k=0;k <= sum_Box;k++){ if(j-Box-k >= 0) F[j]=max(F[j],F[j-Box-k]+thing[k]); } } } printf("%d\n",F[v]); } return 0; }原文链接:https://www.f2er.com/javaschema/284921.html