假题害人、、 明明说了是一棵树,却还要强行加一组坑爹数据 所以网上的题解挂了好多
这题是很综合的树上背包问题、 由依赖关系转化为一些枚举来跑多重背包
由于是 “一棵树” 所以放心根据高低级建边
转移的时候除传统背包外 还需要多加一维 存往上进几个该装备用于合成
父节点合并信息时用01背包,把每个儿子的花费细分 枚举装填合并时再把自己并入
根据代码 会有疑问,就是再枚举儿子的时候会不会有需求没有被满足
因为需求个数的儿子一定满足,g里所有满足的情况都是上一个物品满足的情况(if),,所以这样写是不会有问题的,不满足的情况没有被转移
码:
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
vector<int>xq1[60];
vector<int>xq2[60];
int n,m,sx[60],f[60][150][2017],g[2017],c[60],v[60],ans,i,j,t,x,y,f2[2017];
char ch;
bool si[60],woc;
void dp(int o)
{
int i,j,k,l;
if(xq1[o].size()==0)
{ sx[o]=min(sx[o],m/c[o]);
for(i=0;i<=sx[o];i++)
for(j=i;j<=sx[o];j++)
f[o][i][j*c[o]]=(j-i)*v[o];
return;
}
sx[o]=9999999;
for(i=0;i<xq1[o].size();i++)
{
dp(xq1[o][i]);
sx[o]=min(sx[o],sx[xq1[o][i]]/xq2[o][i]);
// g[o]+=xq2[o][i]*c[xq1[o][i]];
}
for(i=0;i<=sx[o];i++)f[o][i][0]=0;
for(i=0;i<xq1[o].size();i++)
for(j=0;j<=sx[o];j++)
{
for(k=0;k<=m;k++)g[k]=f[o][j][k];
for(k=0;k<=m;k++)f[o][j][k]=-1;
for(k=m;k>=0;k--)
for(l=k;l>=0;l--)
{
if(g[k-l]!=-1&&f[xq1[o][i]][j*xq2[o][i]][l]!=-1)
f[o][j][k]=max(f[o][j][k],g[k-l]+f[xq1[o][i]][j*xq2[o][i]][l]),ans=max(ans,f[o][j][k]);
}
}
for(i=0;i<=sx[o];i++)
for(j=i;j<=sx[o];j++)
for(k=0;k<=m;k++)
{
if(f[o][j][k]!=-1) f[o][i][k]=max(f[o][i][k],f[o][j][k]+(j-i)*v[o]),ans=max(ans,f[o][i][k]);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%d",&v[i]);
scanf("%c",&ch);while(ch==' ')scanf("%c",&ch);
if(ch=='A')
{
woc=1;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&x,&y);
xq1[i].push_back(x);
xq2[i].push_back(y);
si[x]=1;
}
}else
{
scanf("%d%d",&x,&y);
c[i]=x;
sx[i]=y;
}
}
memset(f,-1,sizeof(f));
if(woc==0)
{ memset(f2,-1,sizeof(f2));
f2[0]=0;
for(i=1;i<=n;i++)
for(j=1;j<=sx[i];j++)
for(int k=m;k>=c[i];k--)
{
if(f2[k-c[i]]!=-1)f2[k]=max(f2[k],f2[k-c[i]]+v[i]),ans=max(ans,f2[k]);
}
printf("%d",ans);
return 0;
}
for(int i=1;i<=n;i++)if(!si[i])dp(i);
printf("%d",ans);
}