树上背包。
简单的树形$dp$,计算出摧毁每一个节点所需的最小费用,背包即可。
#include<bits/stdc++.h> using namespace std; struct X { int fa; int in; int ip; int c; }s[2010]; int dp[2010][20010]; int cost[2010]; int f[20010]; vector<int>g[2010]; int n,root,ans; void dfs(int x) { if(g[x].size()==0) { cost[x]=s[x].c; return ; } for(int i=0;i<g[x].size();i++) { int to=g[x][i]; dfs(to); } for(int j=1;j<=s[x].in;j++) f[j]=dp[x][j]=0x7FFFFFFF; for(int i=0;i<g[x].size();i++) { int A = cost[g[x][i]],B = s[g[x][i]].ip; if(A==0x7FFFFFFF) continue; for(int j=1;j<=s[x].in;j++) f[j]=0x7FFFFFFF; for(int j=0;j<=s[x].in;j++) { if(dp[x][j]==0x7FFFFFFF) continue; f[min(s[x].in,j+B)] = min(f[min(s[x].in,j+B)],dp[x][j] + A); } for(int j=0;j<=s[x].in;j++) dp[x][j] = min(dp[x][j],f[j]); } cost[x] = dp[x][s[x].in]; if(cost[x]!=0x7FFFFFFF) cost[x] = cost[x] + s[x].c; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d%d%d",&s[i].fa,&s[i].in,&s[i].ip,&s[i].c); if(s[i].fa==0) root=i; g[s[i].fa].push_back(i); } ans=0x7FFFFFFF; dfs(root); ans=cost[root]; if(ans!=0x7FFFFFFF) printf("%d ",ans); else printf("-1 "); return 0; }