题目链接 https://www.luogu.com.cn/problem/P2014
题目描述
在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习。现在有 NN 门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程 a 是课程 b 的先修课即只有学完了课程 a,才能学习课程 b)。一个学生要从这些课程里选择 MM 门课程学习,问他能获得的最大学分是多少?
输入
7 4
2 2
0 1
0 4
2 1
7 1
7 6
2 2
输出
13
#include <iostream>
using namespace std;
const int maxn = 6 * 1e3 + 10;
int n,m,num;
int dp[maxn][305],head[maxn];
struct node {
int to, next;
} ed[maxn];
void add(int x, int y) {
ed[++num].next = head[x];
ed[num].to = y;
head[x] = num;
}
//tree_dp(x)的作用就是算出以x为节点时,分别选0~m个节点各自的最大值
void tree_dp(int x) {
for (register int i = head[x]; i; i = ed[i].next) {
int v = ed[i].to;
tree_dp(v);
//倒序枚举,使用 to 节点的 f 数组更新 x 节点的 f 数组
for(register int j=m;j>=1;--j) {
for(register int k=1;k<=j-1;++k) {
dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[v][k]);
}
}
}
}
int main() {
cin >> n >> m;
for(register int i=1,a;i<=n;++i) {
cin>>a>>dp[i][1];
add(a,i);
}
m++; // 由于 0 号节点的参与,m 需要自加1
tree_dp(0);
cout << dp[0][m] << endl;
return 0;
}