AcWing 286. 选课
考察:树形dp
关于本题的相关题目 10. 有依赖的背包问题 和 1074. 二叉苹果树 都是一个套路.
思路:
有依赖的背包问题套模板题.关于几点需要再修正:
- 绝对不要在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].
- 那为什么二叉苹果树不需要呢? 因为二叉苹果树是将边权视作点权.而那道题不是加的w[u]而是加w[v] 这道题加w[v]是否可行. 试了一下可以,但那样f[u][j]就变成了在u的子树中选j个点,此点不包括u.私以为这里是设置了一个虚根才能这样求,有依赖的背包问题的f[u][j]是包含u的,私以为根节点没有用处的可以用二叉苹果树那样求.
-
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 }
- 在外面重新加入w[u]的时候要倒序.因为f[u][j-1]会比f[u][j]先更新.但我们需要的未更新的值.
- 这里是假设一个虚拟点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 }