(树的直径模板)P4408 逃学的小孩

题目链接:P4408

 

题目大意:

一棵树(应该是无根树),让你找到树的直径,并且再找除直径端点A,B以外的另一个点C,使得AB+BC最大(并且满足BC < AC)。

 

解题思路:

树的直径就用两次dfs就能求出来,然后O(n)遍历除端点外的每一个点,找到满足答案的最大解。

 

参考代码:

 1 // 树的直径
 2 // dfs方法
 3 // 洛谷P4408
 4 #include <iostream>
 5 #include <cstdio>
 6 #include <cstring>
 7 #include <cmath>
 8 #include <algorithm>
 9 #include <queue>
10 #include <vector>
11 #include <stack>
12 #define N 200010
13 #define int long long
14 using namespace std;
15 struct EDGE
16 {
17     int v;
18     int ti;
19 };
20 vector<EDGE> e[N]; // 邻接表存树(图),因有权值,所以用结构体
21 int d[N]; // 表示一个端点到其它点的距离
22 int td[N]; // 表示另一个端点到其他点的距离
23 inline int read()
24 {
25     int x = 0, y = 1; char c = getchar();
26     while(c < '0' || c > '9') {if(c == '-') y = -1; c = getchar();}
27     while(c >= '0' && c <= '9') x = x*10+c-'0', c = getchar();
28     return x*y;
29 }
30 void dfs(int u, int fa) // 求直径
31 {
32     for(int i = 0; i < e[u].size(); i++)
33     {
34         if(e[u][i].v != fa)
35         {
36             d[e[u][i].v] = d[u]+e[u][i].ti;
37             dfs(e[u][i].v,u);
38         }
39     }
40 }
41 void tdfs(int u, int fa)
42 {
43     for(int i = 0; i < e[u].size(); i++)
44     {
45         if(e[u][i].v != fa)
46         {
47             td[e[u][i].v] = td[u]+e[u][i].ti;
48             tdfs(e[u][i].v,u);
49         }
50     }
51 }
52 signed main()
53 {
54     int n,m;
55     int u,v,ti;
56     int AB,BC;
57     int A,B;
58     n = read();
59     m = read();
60     for(int i = 0; i < m; i++)
61     {
62         u = read();
63         v = read();
64         ti = read();
65         e[u].push_back({v,ti});
66         e[v].push_back({u,ti}); // 无向图
67     }
68     dfs(1,-1);
69     AB = -1;
70     for(int i = 1; i <= n; i++)
71     {
72         if(d[i] > AB)
73         {
74             AB = d[i];
75             A = i;
76         }
77         d[i] = 0;
78     }
79     dfs(A,-1);
80     AB = BC = -1;
81     for(int i = 1; i <= n; i++)
82         if(d[i] > AB)
83             AB = d[i],B = i; // AB即为直径
84     tdfs(B,-1);
85     for(int c = 1; c <= n; c++) // d[]是所有点到A的距离,td[]是所有点到B的距离,找一个c,使
86     {                           // AB+BC最大,并且BC < AC,即td[c] < d[c]
87         int mind = min(d[c],td[c]);
88         if(mind > BC)
89             BC = mind;
90     }
91     printf("%lld",AB+BC);
92     return 0;
93 }

 

posted @ 2020-11-17 18:03  不敢说的梦  阅读(125)  评论(0)    收藏  举报