二叉苹果树——树形dp
P2015 二叉苹果树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
呜呜呜呜,真的是一道厉害题(至少对目前的我来说),研究了一个小时。
首先,因为我们不知道一对坐标中,谁是父亲,谁是儿子,所以用无向图把二者连起来,但最后dfs的时候还是只用其中一个。
状态表示:i的子树上保留j条边时苹果的最大值 q是最大边数,n是结点数
状态计算:f [ i , j ] = max ( f [ 左 , k ] + val [ i , 左 ] + f [ i , q-k-1 ] )
其中,左代表i的左儿子。f [ 左 , k ] 代表i的左儿子的子树上保留k条边时苹果的最大值, val [ i , 左 ] 表示从i到左儿子的边上结出来的苹果数量,f [ i , q-k-1 ]表示i的右儿子的苹果最大值。
k的范围是0到q-1,那么右节点的边数就是q-k-1啦
为什么k最大是q-1,而不是q呢?因为i到左结点或者右节点还要连一条边呀,所以总边数-1。
注意for循环要倒着来
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=352; 4 int g[N][N],f[N][N]; 5 bool st[N]; 6 vector<int> son[N]; 7 int n,q; 8 9 void dfs(int u) 10 { 11 st[u]=1; 12 for(int i=0;i<son[u].size();i++) 13 { 14 int y=son[u][i]; 15 if(st[y])continue; 16 st[y]=1; 17 dfs(y); 18 for(int j=q;j>=1;j--) 19 { 20 for(int k=j-1;k>=0;k--) 21 f[u][j]=max(f[u][j],g[u][y]+f[y][k]+f[u][j-k-1]); 22 } 23 } 24 } 25 26 int main() 27 { 28 scanf("%d%d",&n,&q); 29 for(int i=1;i<=n-1;i++) 30 { 31 int x,y,z;scanf("%d%d%d",&x,&y,&z); 32 g[x][y]=g[y][x]=z; 33 son[x].push_back(y); 34 son[y].push_back(x); 35 } 36 37 dfs(1); 38 printf("%d\n",f[1][q]); 39 40 return 0; 41 }