开始我的想法是对于加了附件的物品当成新的做,结果发现好像并不行啊,会有重复计算的存在
所以直接01背包是不行了,然后我看到网上的题解,有两种方法,一种是分组背包(看起来处理好麻烦qwq),还有种是树形背包,正好没学过2333333,来愉快的学一下
这个题如果用树形背包来做的话,是把主件当成根节点,建一棵树,因此就避免了重复计算,但是如果只是这样会形成森林,因此我们把0作为所有主件的根节点
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; struct in { int fr,to,ne; }ter[120]; int n,m,tail,v[65],p[65],x,y,z,dp[65][32010],head[120]; inline void build(int f,int l)//建出一棵树来,把附件挂在树上,这样就可以避免01背包重复使用的乱七八糟的问题了 { ter[++tail]=(in){f,l,head[f]},head[f]=tail; } void dfs(int no,int w) { if(w<=0) return; for(int i=head[no];i>0;i=ter[i].ne) { int t=ter[i].to; for(int j=0;j<=w-v[t];j++)//先初始化子树的根节点 dp[t][j]=dp[no][j];//以前取好的物品一定取 dfs(t,w-v[t]);//继续往下面找 for(int j=v[t];j<=w;j++)//然后用下面的选取方案来更新上层 dp[no][j]=max(dp[no][j],dp[t][j-v[t]]+p[t]); } } int main() { memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d",&x,&y,&z),v[i]=x,p[i]=x*y,build(z,i); dfs(0,n); printf("%d",dp[0][n]); }