树上分组背包模型,
即每个子树选一种状态,状态为f[x][y]表示以x为根的子树中选y个的最大价值,怎么选并没有影响
注意y>=1则x必须选,即x必须先选了,y即其子节点才能选
同样是森林,需要建立虚点N+1连向无先行课的课
#include<iostream> #include<cstdio> #define ri register int #define u int namespace opt { inline u in() { u x(0),f(1); char s(getchar()); while(s<'0'||s>'9') { if(s=='-') f=-1; s=getchar(); } while(s>='0'&&s<='9') { x=(x<<1)+(x<<3)+s-'0'; s=getchar(); } return x*f; } } using opt::in; #define NN 305 namespace mainstay { u N,M,cnt,h[NN],v[NN],id[NN],f[NN][NN]; struct node{ u to,next; }a[NN]; inline void add(const u &x,const u &y){ a[++cnt].to=y,a[cnt].next=h[x],h[x]=cnt; } void dfs(const u &x){ for(ri i(h[x]);i;i=a[i].next){ u _y(a[i].to); dfs(_y); for(ri j(M);j>=1;--j){ for(ri k(0);k<=j;++k){//不理解蓝书上的话(说是要倒序才正确),这样正序枚举可以过 f[x][j]=std::max(f[x][j],f[x][j-k]+f[_y][k]); } } } if(x^(N+1)){ for(ri i(M);i>=1;--i){ f[x][i]=f[x][i-1]+v[x]; } } } inline void solve(){ N=in(),M=in(); for(ri i(1);i<=N;++i){ u _a(in()),_b(in()); v[i]=_b; if(_a) add(_a,i); else add(N+1,i); } dfs(N+1); std::cout<<f[N+1][M]; } } int main() { //freopen("x.txt","r",stdin); std::ios::sync_with_stdio(false); mainstay::solve(); }