Jzoj5661 药香沁鼻
有依赖关系的树形背包,算是又积累了一种做法
一个经典的做法就是设f[x][j]表示在x子树内,容量为j的最大获利
那么转移可以写成 f[x][j]=max{f[x][j],f[x][j-k]+f[v][k]} v是x的子树
我们在dp时记录背包的剩余空间,就可以得到80分
一个更好的优化就是用dfs序,复杂度直接下降为O(nm)
当然最快的做法还是直接在树上做,我们还是设f[x][j]表示x节点子树取到最大的答案
那么f[x][j]=max(f[x][j],f[x][j-w[y]]+v[u]) 发现转移非常快,加上记录背包的剩余空间,可以非常快的通过
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 5010
using namespace std;
struct edge{ int v,nt; } G[N];
int n,m,cnt,h[N],f[N][10010],v[N],w[N];
inline void gmax(int& x,int y){ x<y?x=y:0; }
inline void adj(int x,int y){
G[++cnt]=(edge){y,h[x]}; h[x]=cnt;
}
inline void dfs(int x,int m){
for(int y,i=h[x];i;i=G[i].nt){
y=G[i].v;
if(m<w[y]) continue;
memcpy(f[y],f[x],m-w[y]+1<<2);
dfs(y,m-w[y]);
for(int j=m;j>=w[y];--j)
gmax(f[x][j],f[y][j-w[y]]+v[y]);
}
}
int main(){
freopen("medicine.in","r",stdin);
freopen("medicine.out","w",stdout);
scanf("%d%d",&n,&m);
for(int x,i=1;i<=n;++i){
scanf("%d%d%d",w+i,&x,v+i);
if(x!=i) adj(x,i);
}
dfs(1,m-w[1]);
for(int j=m-w[1];j;--j) **f=max(**f,f[1][j]);
printf("%d\n",**f+v[1]);
}