樹的直徑
定義 性質:
樹的直徑是樹上最長的鏈,即樹上任意兩點間距離的最大值,可能有多條。
若樹無邊權,則所有直徑的中點相同。
求法:
兩次 \(DFS\)。
第一次,以任意節點為根,搜尋到距離自己最遠的點,這個點就是直徑的一個端點。
第二次,以第一次求得的點為根,搜尋到距離自己最遠的點,這個點就是另一個端點。
長度和路徑可以在 \(DFS\) 中求得。
時間複雜度:\(\Theta(N)\)
程式碼:
#include<iostream>
#include<vector>
#include<cstring>
#define int long long
using namespace std;
const int N = 100010;
int n;
vector<int> G[N];
int le, n1, n2, dia[N]; // 直徑長度,一個端點,dfs次數,節點
int de[N];
void predfs(int u, int fa)
{
if(de[u] > le)
{
le = de[u]; // 更新長度
n2 = u; // 更新端點
}
for(int i=0; i<G[u].size(); i++)
{
int v = G[u][i];
if(v == fa)
continue;
de[v] = de[u] + 1;
if(n1)
dia[v] = u; // 儲存路徑
predfs(v, u);
}
}
signed main()
{
cin >> n;
for(int i=1; i<n; i++)
{
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
predfs(1, 0);
memset(de, 0, sizeof(de));
le = 0, n1 = n2;
de[n2] = 1;
predfs(n2, 0);
cout << n1 << ' ' << n2 << ' ' << le << '\n';
// 端點和長度
int t = n2;
for(int i=1; i<=le; i++)
{
cout << t << ' ';
t = dia[t];
} // 路徑
return 0;
}