二叉苹果树——树形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循环要倒着来

 

 

 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 }
View Code

 

posted @ 2022-04-05 17:10  wellerency  阅读(35)  评论(0编辑  收藏  举报