树形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 }

猜你喜欢

转载自www.cnblogs.com/very-beginning/p/12460401.html