树形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]); }