%一发hzwer大爷
树形背包dp
1.处理每个装备的上限--->普通装备总钱数除以单价,特殊装备--->子装备的上限除以需要的数量,最后再和总钱数/单价取min,单价是合成这个特殊装备的价值
2.定义f[i][j][k]表示第i件物品,j件用于向上传递,造这件装备一共花费了k时的最大贡献
3.对于以 x为根的子树,枚举合成的数量e,然后剩余的钱去买子树单独的装备
4.我们定义g[i][j]表示x的前i个子树,花费j的最大贡献
显然g[i][j]=max(g[i][j],g[i-1][j-now]+f[to][e*need][now])now是第i棵子树用的钱数,need是合成一件需要数量
5.然后用g去更新f[x][][]
6.假想一个根节点,把所有贡献更新到他身上
最后取个max
代码
//By ACerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=55;
const int inf=2e9;
int n,m,tot;
int f[M][M*2][M*M];
int c[M],on[M],lim[M];
int g[M][M*M],h[M][M*M],vis[M];
int to[M],nxt[M],head[M],w[M],cnt;
inline int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void add(int x,int y,int z)
{
to[++cnt]=y;nxt[cnt]=head[x];w[cnt]=z;head[x]=cnt;vis[y]=1;
return ;
}
inline void getleaf(int x)
{
lim[x]=min(lim[x],m/on[x]);//更新上限
for (int i=0;i<=lim[x];i++)
for (int k=i;k<=lim[x];k++)
f[x][i][k*on[x]]=(k-i)*c[x];//处理f数组,向上传递的装备没有单独贡献,所以是(k-i)个装备有贡献
return ;
}
inline void tdp(int x)
{
if (!head[x]) return (void)(getleaf(x));
lim[x]=inf;
for (int i=head[x];i;i=nxt[i])
{
tdp(to[i]);
lim[x]=min(lim[x],lim[to[i]]/w[i]);
on[x]+=(w[i]*on[to[i]]);
}
lim[x]=min(lim[x],m/on[x]);
memset(g,-0x3f,sizeof(g));g[0][0]=0;
for (int i=lim[x];i>=0;i--)
{
int all=0;
for (int k=head[x];k;k=nxt[k])
{
all++;
for (int j=0;j<=m;j++)
for (int e=0;e<=j;e++)
g[all][j]=max(g[all][j],g[all-1][j-e]+f[to[k]][i*w[k]][e]);
}
for (int k=0;k<=i;k++)
for (int j=0;j<=m;j++)
f[x][k][j]=max(f[x][k][j],g[all][j]+c[x]*(i-k));//和上面的普通装备的处理一样
}
return ;
}
signed main()
{
n=read();m=read();char s[5];
for (int i=1;i<=n;i++)
{
c[i]=read();scanf("%s",s);
if (s[0]=='A')
{
int x=read(),y,z;
while (x--) y=read(),z=read(),add(i,y,z);
}
else on[i]=read(),lim[i]=read();
}
memset(f,-0x3f,sizeof(f));int ans=0;
for (int i=1;i<=n;i++)
if (!vis[i])
{
tdp(i);tot++;
for (int k=0;k<=m;k++)
for (int j=0;j<=k;j++)
for (int e=0;e<=lim[i];e++)
h[tot][k]=max(h[tot][k],h[tot-1][j]+f[i][e][k-j]);
}
for (int i=0;i<=m;i++)
ans=max(ans,h[tot][i]);
cout<<ans;
return 0;
}