1466. Reorder Routes to Make All Paths Lead to the City Zero

練習日期:2026-02-24

難度:Medium

類型:Depth-First Search、Breadth-First Search、Graph

📘 題目敘述

n 個城市,編號從 0n - 1。有 n - 1 條道路,把所有城市連成一棵樹。

每條道路原本都有方向,connections[i] = [a, b] 表示有一條道路從城市 a 指向城市 b

你可以改變一些道路的方向。請回傳最少需要改變方向的道路數量,才能讓每個城市都可以沿著道路走到城市 0

條件限制

  • 2 <= n <= 5 * 10^4
  • connections.length == n - 1
  • connections[i].length == 2
  • 0 <= a_i, b_i <= n - 1
  • a_i != b_i

🧠 解題思路

我這題的想法是把原本有方向的邊,轉成「無向圖 + 額外資訊」,然後從 0 出發 DFS 一次就能算出答案。

做法是這樣:

對每條原始邊 a -> b

  • 我在 g[a] 放一條到 b 的邊,並標記 k = 0
  • k = 0 的意思是:這條邊方向是「離開 0 的方向」(如果我從 0 的 DFS 走到它,就代表它需要被反轉)
  • 我在 g[b] 放一條到 a 的邊,並標記 k = 1
  • k = 1 的意思是:這條邊方向本來就是「往 0 的方向」(從 b 走到 a 不需要反轉)

接著我從城市 0 做 DFS:

  • 每當我走一條 k == 0 的邊去拜訪沒看過的城市,代表這條原本方向是「從目前節點往外」的,若要讓大家都能走回 0,就必須把它反轉,所以 ans++
  • k == 1 的邊代表原本就是朝向 DFS 起點方向,不需要反轉

因為整張圖是一棵樹,每個城市只會被走到一次,所以 DFS 過程中把所有需要反轉的邊累加起來,就是最小答案。

所有變數

  • g:鄰接表,g[i](to, k)
  • to:相鄰城市
  • k == 0:代表原始邊方向是 i -> to(走這條邊會需要反轉)
  • k == 1:代表原始邊方向是 to -> i(走這條邊不需要反轉)
  • visit:記錄城市是否已 DFS 走過,避免走回頭造成重複
  • ans:需要反轉的邊數(最後回傳)

🪜 主要流程步驟

1. 建立「無向鄰接表 + 方向標記」

我把每條輸入 a -> b 同時加兩條邊:

  • g[a].push_back({b, 0})
  • g[b].push_back({a, 1})

這樣我在 DFS 時永遠可以走到鄰居,但用 k 判斷「原本方向」是否要反轉。


2. 從城市 0 做 DFS,確保每個城市只走一次

我用 visit 防止重複:

  • 每到一個城市 i,先 visit[i] = true
  • 掃描 g[i] 的所有鄰居 (to, k)
  • 如果 to 已走過就跳過
  • 否則表示這條邊是樹上通往未拜訪子節點的邊

3. 走到未拜訪鄰居時,遇到 k==0 就代表必須反轉

當我要從 i 走到 to

  • 如果 k == 0,代表原本方向是 i -> to
  • 但我們希望 to 能走回 0,這條邊應該要變成 to -> i
  • 所以這條邊必須反轉,ans++

然後遞迴 check(to) 繼續走下去。


4. DFS 結束後回傳 ans

因為樹的每條邊只會在 DFS 走向未訪問節點時被處理一次,所有需要反轉的邊都會被正確累加,最後回傳 ans

⏱️ 複雜度

  • 時間複雜度:O(n),因為是樹,邊數 n-1,每個節點和邊都只會被處理一次。
  • 空間複雜度:O(n),鄰接表 g 需要存 2*(n-1) 條邊,visit 也需要 n,遞迴深度最壞 O(n)

💻 程式碼實作

class Solution {
public:
    vector<vector<pair<int, int>>> g; // g[0]是點 g[1]0是不動1是反
    vector<bool> visit;
    int ans = 0;

    void check(int i) {
        visit[i] = true;
        for (auto [to, k] : g[i]) {
            if (visit[to]) {
                continue;
            } else {
                if (k == 0) {
                    ans++;
                }
                check(to);
            }
        }
    }

    int minReorder(int n, vector<vector<int>>& connections) {
        g.assign(n, {});
        visit.assign(n, false);
        for (auto& x : connections) { // auto自動抓型態
            int a = x[0], b = x[1];
            g[a].push_back({b, 0});
            g[b].push_back({a, 1});
        }
        check(0);
        return ans;
    }
};

https://leetcode.com/problems/reorder-routes-to-make-all-paths-lead-to-the-city-zero/

作者: scottnick
撰寫日期: 2026-02-24
類別:
原文連結: https://scottnick.github.io/cpp-notes/leetcode75/1466-reorder-routes-to-make-all-paths-lead-to-the-city-zero.html