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]);
}

posted @ 2018-04-20 20:57  扩展的灰(Extended_Ash)  阅读(148)  评论(0编辑  收藏  举报