树形dp--P2014 [CTSC1997]选课

*传送

思路:因为有的学科有直接先修课(选了先修课才能选当前课程),所以我们可以让当前课程指向他的先修课,这样只要先修课没有选,他的子树就没有办法选。

确定状态:$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 }

 

 

posted @ 2020-03-11 09:12  小又又  阅读(240)  评论(0编辑  收藏  举报