(树的直径模板)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 }

浙公网安备 33010602011771号