题目:https://www.luogu.org/problemnew/show/P2014
树状DP,注意枚举当前子树中选几个时的边界。
代码如下:
#include<iostream> #include<cstdio> using namespace std; int n,m,k,s[305],ct,cnt[305],dp[305][305],size[305]; struct N{ int to,next; }edge[305]; void add(int x,int y) { ct++; edge[ct].to=y; edge[ct].next=cnt[x]; cnt[x]=ct; } void f(int nw) { for(int i=cnt[nw];i;i=edge[i].next) { int u=edge[i].to; f(u); for(int j=min(size[nw]+size[u],m-1);j>=0;j--)// { for(int k=max(0,j-size[nw]);k<j&&k<=size[u];k++)// dp[nw][j]=max(dp[nw][j],dp[nw][j-k]+dp[u][k]); } size[nw]+=size[u]; } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d%d",&k,&s[i]); add(k,i); } for(int i=1;i<=n;i++)size[i]=1,dp[i][1]=s[i]; for(int i=cnt[0];i;i=edge[i].next) { int u=edge[i].to; f(u); for(int j=min(size[0]+size[u],m);j>=0;j--) { for(int k=max(0,j-size[0]);k<=size[u]&&k<=j;k++) dp[0][j]=max(dp[0][j],dp[0][j-k]+dp[u][k]); } size[0]+=size[u]; } printf("%d",dp[0][m]); return 0; }