洛谷P2014 选课 ——树形DP

树形DP,链接表存树,把没有先修课的看做根节点的儿子点,第一层枚x点的子节点,记当前子节点为i,第二层枚x及x子树总共选多少科,记为j,第三层枚x及x子树总共选多少科,记为k,故x点处最优解即为i处选j-k科的最优解加上x除i子树以外其他子树选k科的最优解,即: 

        dp[x][j]=max{dp[x][j],dp[i][j-k]+dp[x][k]

#include<bits/stdc++.h>
using namespace std;
struct cyka{
    int to,pre;
}e[1000000];
int cnt,f[1000][1000],head[100000],n,m;
void add(int from,int to){                //链接表
    e[++cnt].pre=head[from];
    e[cnt].to=to;
    head[from]=cnt;
}
void dp(int x){//当前点
    for(int i=head[x];i;i=e[i].pre){      //枚子点
        int y=e[i].to;
        dp(y);       //动规子点
        for(int j=m+1;j>0;j--){          //枚从x开始的选科个数
            for(int k=1;k<=j;k++){   //枚从i开始的选科个数
                f[x][j]=max(f[x][j],f[y][j-k]+f[x][k]);  //状态转移方程
            }
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        cin>>f[i][1];
        add(x,i);
    }
    dp(0);
    printf("%d\n",f[0][m+1]);
}

猜你喜欢

转载自www.cnblogs.com/passione-123456/p/11198795.html
今日推荐