tyvj1051 选课

/*
分组背包+树形dp:以树的深度作为阶段,以节点编号作为一维状态, 
思路:首先dp[u][t]表示选择以第u门课为根,选了t门课的最大值,
    状态转移方程dp[u][t]=max(所有儿子中凑出t-1门课)+s[u],
    那么如何在所有儿子中凑出t-1门课,需要用到分组背包,每个儿子为一组,设v是u的一个儿子,那么第v组背包中有t-1件物品,第j件物品体积为j,价值就是dp[v][j](以v为根的选了j门课的最大值) 
     
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;

int n,m,dp[305][305],s[305];
vector<int> son[305];

void dfs(int u){
    dp[u][0]=0;
    for(int i=0;i<son[u].size();i++){
        int v=son[u][i];
        dfs(v);
        for(int t=m;t>=0;t--)//状态:分组背包逆序循环背包容量 
            for(int j=0;j<=t;j++)//决策:为什么进阶指南上要求对决策进行逆序遍历? 
                dp[u][t]=max(dp[u][t],dp[u][t-j]+dp[v][j]); 
    }
    if(u!=0)//必须算上这门课 
        for(int t=m;t>0;t--) 
            dp[u][t]=dp[u][t-1]+s[u]; 
}

int main(){
    while(scanf("%d%d",&n,&m)==2){
        for(int i=1;i<=n;i++){
            int u;
            scanf("%d%d",&u,&s[i]);
            son[u].push_back(i);
        }
        dfs(0);
        printf("%d
",dp[0][m]);
    }
}
原文地址:https://www.cnblogs.com/zsben991126/p/10223733.html