-----------------------------
链接:Miku
------------------------------
此文不是正解,而且主要内容都在代码和注释上
------------------------------
这是暴力分组背包做法
----------------------------
对于每一个主件及其附件,我们的选择是有限的,而且这道题中说了最多两个附件,那么
我们完全可以枚举每一种组合,然后组合成一件新的物品,并且属于同一个集合,然后对处理后的新物品们
跑分组背包就行了
---------------------------
#include<iostream> #include<cstdio> using namespace std; long long n,m; long long x,y,z; long long num[7000];//存该类别物品出现数量 long long cnt;//统计类别数 struct th{ long long w; long long v; long long l; } t[7000],ft[7000];//一开始的和最后的物品 long long le[7000];//类别 long long f;//用来存物品的指针 long long po[7000][7000];//记录一下每一类物品的每一件的的存储下标 long long fn;//计数 long long fnum[7000];//同num long long dp[32010]; void add(long long w,long long v,long long l){ fn++; ft[fn].l=l; ft[fn].v=v; ft[fn].w=w; } int main(){ scanf("%lld%lld",&n,&m); for(long long i=1;i<=m;++i){ scanf("%lld%lld%lld",&x,&y,&z); if(z==0){ y=x*y; cnt++; f++;//记录这个主件 num[cnt]++; t[f].v=x; t[f].w=y; t[f].l=cnt; le[i]=cnt; po[cnt][1]=f; }else{ y=x*y; f++; t[f].v=x; t[f].w=y;//记录这个附件 t[f].l=le[z]; num[le[z]]++;//统计 po[le[z]][num[le[z]]]=f;//表示这一类的第num【le【z】】个物品的下标 } } for(long long i=1;i<=cnt;++i){//数据很小,暴力合并 if(num[i]==1){ add(t[po[i][1]].w,t[po[i][1]].v,i); } if(num[i]==2){ add(t[po[i][1]].w+t[po[i][2]].w,t[po[i][1]].v+t[po[i][2]].v,i); add(t[po[i][1]].w,t[po[i][1]].v,i); } if(num[i]==3){ add(t[po[i][1]].w+t[po[i][2]].w,t[po[i][1]].v+t[po[i][2]].v,i); add(t[po[i][1]].w,t[po[i][1]].v,i); add(t[po[i][1]].w+t[po[i][3]].w,t[po[i][1]].v+t[po[i][3]].v,i); add(t[po[i][1]].w+t[po[i][3]].w+t[po[i][2]].w,t[po[i][1]].v+t[po[i][3]].v+t[po[i][2]].v,i); num[i]=4;//会变成总共四个 } } long long summ=0;//开始跑分组背包 for(long long i=1;i<=cnt;++i){ summ+=num[i-1]; for(long long j=n;j>=0;--j){ for(long long k=1;k<=num[i];++k){ if(j>=ft[summ+k].v) dp[j]=max(dp[j],dp[j-ft[summ+k].v]+ft[summ+k].w); } } } printf("%lld",dp[n]);//end return 0; }