小Ho擁有一棵由N個節點(標號1至N)和N-1條邊構成的樹形玩具。小Hi出了一道題目:找出樹中距離最遠的兩個節點之間的距離,距離定義為路徑上邊的數量。這就是經典的「樹的直徑」問題。
設樹的直徑端點為v1和v2。有一個關鍵性質:從任意節點u出發,走到的最遠節點一定是v1或v2其中之一。因此,我們可以通過兩次圖搜尋(BFS或DFS)來求解:
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int MAXN = 100005;
vector<int> tree[MAXN];
bool vis[MAXN];
int farthest_node, max_len;
void dfs(int u, int len) {
vis[u] = true;
if (len > max_len) {
max_len = len;
farthest_node = u;
}
for (int v : tree[u]) {
if (!vis[v]) dfs(v, len + 1);
}
}
int main() {
int N;
while (scanf("%d", &N) == 1) {
for (int i = 1; i <= N; ++i) tree[i].clear();
for (int i = 1; i < N; ++i) {
int a, b; scanf("%d%d", &a, &b);
tree[a].push_back(b);
tree[b].push_back(a);
}
memset(vis, 0, sizeof(vis));
max_len = -1;
dfs(1, 0); // 第一次搜尋找到 v1
int v1 = farthest_node;
memset(vis, 0, sizeof(vis));
max_len = -1;
dfs(v1, 0); // 第二次搜尋找到 v2 及直徑長度
printf("%d\n", max_len);
}
return 0;
}
「兩次DFS/BFS」法利用樹的拓撲性質,以線性時間優雅地解決了樹的直徑問題,是圖論基礎中的經典技巧。