樹直徑

非常罕見

概念

樹直徑就是指樹上最遠的點對的距離,更仔細的說,假設有一個函式 dist(x,y)dist(x, y) 代表節點 xx 與節點 yy 的簡單路徑距離,那數直徑就可以這樣表示:

max1v,undist(u,v)max_{1 \leq v, u \leq n} dist(u, v)

以這張圖為例:

alt text

可以看到 1 和 2 的簡單路徑長度為 3,然後 3 到 4 的簡單路徑程度為 2,而我們要找的樹直徑是 2 到 4 這條距離為 4 的最長路徑。

實作方式

樹直徑的實作方式其實不只一種,而其中簡單的做法就是透過兩次 DFS,那要怎麼透過 DFS 找到樹直徑呢?

具體來說,我們需要執行以下兩個步驟:

  • 從任意點開始做 DFS 並找到最遠的那個點 xx
  • 接著把 xx 當起點繼續做一次 DFS 找到距離點 xx 最遠的點 yy

如此一來,xxyy 的句離就是樹直徑了!

void dfs(int v, int d = 0) {
    vis[v] = true;
    // 如果深度超過目前最大深度就更新
    if (d > maxdeep) {
        // 把最遠的點記錄在 deep 變數中
        deep = v;
        maxdeep = d;
    }
    for (auto e : tree[v]) {
        if (vis[e]) continue;
        vis[e] = true;
        dfs(e, d + 1);
    }
}
 
int main() {
    dfs(1); // 第一次從任意點開始找到最遠的點
    memset(vis, 0, sizeof(vis));
    maxdeep = -1;
    dfs(deep); // 第二次從最遠的點開始找到另外一個最遠的點
    cout << maxdeep << endl; // 最後 maxdeep 就是樹直徑
}

雖然可能看似沒什麼用,不過這是非常經典的問題,APCS 檢定中也曾經直接出現過樹直徑的裸題!