有依赖的背包问题
10. 有依赖的背包问题 - AcWing题库
考虑树形 DP
。
假设我们对于 \(u\),已经计算完毕子节点 \(v\),那么我们应该如何合并方案呢?
有一种方式是指数级枚举子节点的所有选择方案,但是肯定不可行。
回忆一般背包的状态表示,我们可以直接搬过来用:令 \(f[u,j]\) 表示 \(u\) 为根的子树内,共 \(j\) 体积能产生的贡献。
由于以 \(u\) 为根的子树内 \(u\) 必须选择,可以先减去 \(v[u]\),做一遍 DP
,然后最后增加回来即可。
对于每棵子树相互独立,且每棵子树只能选择 \(f[v][0\sim m-v[u]]\),这就是一个分组背包问题了。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define Ed for(int i=h[x];~i;i=ne[i])
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
#define Wh while
const int N=310,M=N;
int n,m;
int h[N],e[M],ne[M],idx,v[N],w[N],f[N][N],tmp[N];//don't forget memset h!
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int x,int fa){
int mm=m-v[x],val=w[x];
Ed{
int v=e[i];
if(v==fa)continue;
dfs(v,x);
Re(j, mm, 0)
E(k, j)f[x][j]=max(f[x][j],f[x][j-k]+f[v][k]);
}
Re(j, m, v[x])f[x][j]=f[x][j-v[x]]+val;
L(j, v[x])f[x][j]=0;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
memset(h,-1,n*4+4);
int rt;
E(i, n){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
~c?add(c,i),0:rt=i;
v[i]=a,w[i]=b;
}
dfs(rt,-1);
printf("%d",f[rt][m]);
return 0;
}