设dp[u][j]为以u为根的子树,选取了j个点所能取得的最大价值,状态转移方程dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k])
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
vector<int>edge[205];
int w[205],dp[205][205],sum[205];
void dfs(int u)
{
int v,len=edge[u].size(),i,j,k;
sum[u]=1; dp[u][1]=w[u]; dp[u][0]=0;
for(i=0;i<len;i++){
v=edge[u][i];
dfs(v);
sum[u]+=sum[v];
for(j=sum[u];j>1;j--){
for(k=1;k<j && k<=sum[v];k++){
dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]);
}
}
}
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m)){
if(!n && !m) break;
int i;
memset(dp,-32,sizeof(dp));
for(i=0;i<=n;i++) edge[i].clear();
for(i=1;i<=n;i++){
int a,b;
scanf("%d%d",&a,&b);
edge[a].push_back(i);
w[i]=b;
}
dfs(0);
printf("%d\n",dp[0][m+1]);
}
return 0;
}
优化后的代码
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
vector<int>edge[205];
int w[205],dp[205][205];
void dfs(int u,int vol)
{
int v,len=edge[u].size(),i,j;
for(i=0;i<len;i++){
v=edge[u][i];
for(j=0;j<=vol-1;j++) dp[v][j]=dp[u][j];
dfs(v,vol-1);
for(j=1;j<=vol;j++) dp[u][j]=max(dp[u][j],dp[v][j-1]+w[v]);
}
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m)){
if(!n && !m) break;
int i;
memset(dp,0,sizeof(dp));
for(i=0;i<=n;i++) edge[i].clear();
for(i=1;i<=n;i++){
int a,b;
scanf("%d%d",&a,&b);
edge[a].push_back(i);
w[i]=b;
}
dfs(0,m);
printf("%d\n",dp[0][m]);
}
return 0;
}