思路:因为有的学科有直接先修课(选了先修课才能选当前课程),所以我们可以让当前课程指向他的先修课,这样只要先修课没有选,他的子树就没有办法选。
确定状态:$f[i][j]$表示选择i节点选j门课程的最大价值
转移方程:$f[u][j]=max(f[u][j],f[to][k]+f[u][j-k])$
其中$u$表示的是当前节点,$to$表示他的子节点
方程式的意义为:$f[u][j]$表示选或不选当前节点,但不选子树,一共选了$j$个课程的最大价值
$f[to][k]+f[u][j-k]$表示选择当前节点,并选择他的$k$个子节点,一共选了$j$个节点的最大价值
*注:初始化的时候$f[i][1]$表示只选择当前节点,他的值就是这门课的学分
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cmath> 5 using namespace std; 6 int n,m; 7 struct node{ 8 int next,to; 9 }ed[305]; 10 int head[305],tot,f[305][305],fa; 11 void add(int u,int v){ 12 ed[++tot].next=head[u]; 13 ed[tot].to=v; 14 head[u]=tot; 15 } 16 void dp(int u){ 17 for (int i = head[u];i;i=ed[i].next){ 18 int to=ed[i].to; 19 dp(to); 20 for (int j = m+1;j >= 1;j--){ 21 for (int k = 0;k < j;k++){ 22 f[u][j]=max(f[u][j],f[to][k]+f[u][j-k]); 23 } 24 } 25 } 26 } 27 int main(){ 28 scanf ("%d%d",&n,&m); 29 for (int i = 1;i <= n;i++){ 30 scanf ("%d%d",&fa,&f[i][1]); 31 add(fa,i); 32 } 33 dp(0); 34 cout<<f[0][m+1]; 35 return 0; 36 }