AcWing 1072. 树的最长路径

原题链接

考察:树形dp

思路:

       从定义出发我们需要枚举所有路径,但直接枚举两个点直接的路径会超时,所以要分类集合枚举.已知树的路径一定会经过某个点,那么我们以点来分类集合.以路径的最高点来分类,经过这个点的最长路径 = 经过此点最长边+经过此点次长边.因此状态转移方程 f[u] = f[v1] +f[v2]+len(u,v1)+len(u,v2).

       我们以哪个点开始dfs,相当于把此点当根

注意:因为是无向的,所以要建立两个方向的边

        关于求次大值以d>最大值与小于最大值分类

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 const int N = 10010;
 7 struct Road{
 8     int to,ne,w,fr;
 9 }road[N<<1];
10 int h[N],idx,ans,f[N];
11 void add(int a,int b,int c)
12 {
13     road[idx].w = c,road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++;
14 }
15 int dfs(int u,int fa)//返回u结点往下的最大长度
16 {
17     int dist = 0,d1 = 0,d2 = 0;
18     for(int i=h[u];i!=-1;i=road[i].ne)
19     {
20         int v = road[i].to;
21         if(v==fa) continue;
22         int d = dfs(v,u)+road[i].w;
23         dist = max(d,dist);
24         if(d>=d1) d2 = d1,d1 = dist;//dist是最大值,不能用dist与d1比较
25         else if(d>d2) d2 = d;
26     }
27     f[u] = d1+d2;
28     return dist;
29 }
30 int main()
31 {
32     int n,root = 1;
33     scanf("%d",&n);
34     memset(h,-1,sizeof h);
35     for(int i=1;i<n;i++)
36     {
37         int a,b,c;
38         scanf("%d%d%d",&a,&b,&c);
39         add(a,b,c); add(b,a,c);
40     }
41     dfs(root,-1);
42     for(int i=1;i<=n;i++) ans = max(ans,f[i]);
43     printf("%d\n",ans);
44     return 0;
45 }

 

posted @ 2021-02-15 16:40  acmloser  阅读(92)  评论(0编辑  收藏  举报