AcWing 286. 选课

原题链接

考察:树形dp

关于本题的相关题目 10. 有依赖的背包问题 和 1074. 二叉苹果树 都是一个套路.

思路:

       有依赖的背包问题套模板题.关于几点需要再修正:

  1. 绝对不要在dfs遍历连接点的时候+w[u].因为f[u][j] = max(f[v][k]+f[u][j-k],f[u][j]);本质是f[u][j] = f[v][k]+f[u][j-k].如果在后面再加一个w[u]的话可能会重复.因为f[u][j-k]更新应该会在f[u][j]之前.而f[u][j-k]已经计入了w[u].
  2. 那为什么二叉苹果树不需要呢?  因为二叉苹果树是将边权视作点权.而那道题不是加的w[u]而是加w[v]
  3. 这道题加w[v]是否可行.  试了一下可以,但那样f[u][j]就变成了在u的子树中选j个点,此点不包括u.私以为这里是设置了一个虚根才能这样求,有依赖的背包问题的f[u][j]是包含u的,私以为根节点没有用处的可以用二叉苹果树那样求.
    1.  1 #include <iostream>
       2 #include <cstring>
       3 #include <algorithm>
       4 using namespace std;
       5 const int N = 310;
       6 int h[N],idx,n,m,w[N],f[N][N];
       7 struct Road{
       8     int fr,to,ne;
       9 }road[N];
      10 void add(int a,int b)
      11 {
      12     road[idx].to = b,road[idx].fr = a,road[idx].ne = h[a],h[a] = idx++;
      13 }
      14 void dfs(int u)
      15 {
      16     for(int i=h[u];i!=-1;i=road[i].ne)
      17     {
      18         int v = road[i].to;
      19         dfs(v);
      20         for(int j=m;j>=0;j--)//不能在for循环里加w[u],会使w[u]重复加入
      21           for(int k=0;k<j;k++)//f[2][4] = f[2][3]+f[4][0]+w[u] f[2][3]已经包含了w[u]
      22             f[u][j] = max(f[v][k]+f[u][j-k-1]+w[v],f[u][j]);//printf("%d %d的值是%d\n",u,j,f[u][j]);
      23     }
      24     f[u][0] = 0;
      25 }
      26 int main()
      27 {
      28     memset(h,-1,sizeof h);
      29     scanf("%d%d",&n,&m);
      30     for(int i=1;i<=n;i++)
      31     {
      32         int x; scanf("%d%d",&x,&w[i]);
      33         add(x,i);
      34     }
      35     dfs(0);
      36     printf("%d\n",f[0][m]);
      37     return 0;
      38 }
      代码
  4. 在外面重新加入w[u]的时候要倒序.因为f[u][j-1]会比f[u][j]先更新.但我们需要的未更新的值.
  5. 这里是假设一个虚拟点0,因为0必选所以m+1
 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N = 310;
 6 int h[N],idx,n,m,w[N],f[N][N];
 7 struct Road{
 8     int fr,to,ne;
 9 }road[N];
10 void add(int a,int b)
11 {
12     road[idx].to = b,road[idx].fr = a,road[idx].ne = h[a],h[a] = idx++;
13 }
14 void dfs(int u)
15 {
16     for(int i=h[u];i!=-1;i=road[i].ne)
17     {
18         int v = road[i].to;
19         dfs(v);
20         for(int j=m;j>=0;j--)//不能在for循环里加w[u],会使w[u]重复加入
21           for(int k=0;k<=j;k++)//f[2][4] = f[2][3]+f[4][0]+w[u] f[2][3]已经包含了w[u]
22             f[u][j] = max(f[v][k]+f[u][j-k],f[u][j]);
23     }
24     for(int i=m+1;i>=1;i--) f[u][i] = f[u][i-1]+w[u];
25     f[u][0] = 0;
26 }
27 int main()
28 {
29     memset(h,-1,sizeof h);
30     scanf("%d%d",&n,&m);
31     for(int i=1;i<=n;i++)
32     {
33         int x; scanf("%d%d",&x,&w[i]);
34         add(x,i);
35     }
36     dfs(0);
37     printf("%d\n",f[0][m+1]);
38     return 0;
39 }

 

posted @ 2021-02-16 19:41  acmloser  阅读(82)  评论(0编辑  收藏  举报