给一棵节点带权的树,找到一个有k个节点的子树,求这个子树的最大权值。

 

dp[u][k]表示以u为根的子树中包含u结点的大小为k的子树的最大权和

  然后对u的每个子节点做分组背包,因为对于u的每个儿子,可以选择分配
   1,2,3...k-1个节点给它

 状态转移方程:

   当节点大小为K时,可以由根节点为u,子树大小为k-t, 加上根节点为v,子树大小为t的状态转移得到(v为u的子节点),即:


   dp[u][k] = max(dp[u][k] , dp[u][k-t]+dp[v][t]);//v是u的儿子节点

#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <algorithm>  
#include <vector>  
using namespace std;
//简单的树形DP
int max(int a,int b){
    return a>b?a:b;
}
const int inf = 1<<30;
int n,k;
int x[202];
int dp[202][202];
vector <int> List[202];

void dfs(int u,int father){
    int i,j;
    for(i=0;i<List[u].size();i++)
    {
        int v=List[u][i];
        if(v==father) 
            continue;
        dfs(v,u);
        
        for(j=k;j>=1;j--)//一定要倒序
        {
            for(int t=1;t<=j;t++)
                dp[u][j]=max(dp[u][j] , dp[u][t]+dp[v][j-t]);
        }
    }
}
int main(){
    scanf("%d %d",&n,&k);
    int i,j,a,b;
    for(i = 0;i <= n;i++) //清空list表
        List[i].clear();
    memset(dp,0,sizeof(dp));
    dp[0][1]=0;//以0为根节点有且只有1个节点字数的最大权重
    for(i=1;i<=n;i++){    
        scanf("%d %d",&b,&dp[i][1]);//以i为根节点有且只有1个节点字数的最大权重
        List[i].push_back(b);
        List[b].push_back(i);
    }
    k++;//多加一个0节点
    dfs(0,-1);
    printf("%d\n",dp[0][k]);//以0为根节点有且只有m个节点字数的最大权重
    return 0;
}