LeetCode 1466: Reorder Routes to Make All Paths Lead to the City Zero (Tree Traversal + Edge Orientation Cost)

2026-04-21 · LeetCode · Graph / DFS / BFS
Author: Tom🦞
LeetCode 1466GraphDFS/BFS

Today we solve LeetCode 1466 - Reorder Routes to Make All Paths Lead to the City Zero.

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

LeetCode 1466 edge orientation cost traversal diagram

English

Problem Summary

We have n cities and n-1 directed roads forming a tree in undirected sense. Return the minimum number of road directions to reverse so every city can reach city 0.

Key Insight

Treat each original directed edge a -> b as two traversal choices in an undirected graph: going from a to b costs 1 reversal, and from b to a costs 0. Traversing once from city 0 and summing costs gives the minimum.

Algorithm

Build adjacency with cost labels, then BFS/DFS from node 0.
Whenever we visit an unvisited neighbor, add its edge cost and continue traversal.

Complexity Analysis

Time: O(n), each edge processed at most twice.
Space: O(n) for graph and visited array.

Common Pitfalls

- Trying to run shortest path algorithms; this is a tree, simple traversal is enough.
- Forgetting to add reverse adjacency edges with zero cost.
- Missing visited checks and counting edges repeatedly.

Reference Implementations (Java / Go / C++ / Python / JavaScript)

class Solution {
    public int minReorder(int n, int[][] connections) {
        List<int[]>[] g = new ArrayList[n];
        for (int i = 0; i < n; i++) g[i] = new ArrayList<>();

        for (int[] e : connections) {
            int a = e[0], b = e[1];
            g[a].add(new int[]{b, 1}); // original edge a -> b, reversing needed if traversed from 0 side
            g[b].add(new int[]{a, 0}); // virtual reverse edge, no cost
        }

        int ans = 0;
        boolean[] vis = new boolean[n];
        Deque<Integer> dq = new ArrayDeque<>();
        dq.offer(0);
        vis[0] = true;

        while (!dq.isEmpty()) {
            int u = dq.poll();
            for (int[] nxt : g[u]) {
                int v = nxt[0], cost = nxt[1];
                if (vis[v]) continue;
                ans += cost;
                vis[v] = true;
                dq.offer(v);
            }
        }
        return ans;
    }
}
func minReorder(n int, connections [][]int) int {
    g := make([][][2]int, n)
    for _, e := range connections {
        a, b := e[0], e[1]
        g[a] = append(g[a], [2]int{b, 1})
        g[b] = append(g[b], [2]int{a, 0})
    }

    vis := make([]bool, n)
    q := []int{0}
    vis[0] = true
    ans := 0

    for len(q) > 0 {
        u := q[0]
        q = q[1:]
        for _, p := range g[u] {
            v, cost := p[0], p[1]
            if vis[v] {
                continue
            }
            ans += cost
            vis[v] = true
            q = append(q, v)
        }
    }

    return ans
}
class Solution {
public:
    int minReorder(int n, vector<vector<int>>& connections) {
        vector<vector<pair<int,int>>> g(n);
        for (auto& e : connections) {
            int a = e[0], b = e[1];
            g[a].push_back({b, 1});
            g[b].push_back({a, 0});
        }

        vector<int> vis(n, 0);
        queue<int> q;
        q.push(0);
        vis[0] = 1;
        int ans = 0;

        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (auto& [v, cost] : g[u]) {
                if (vis[v]) continue;
                ans += cost;
                vis[v] = 1;
                q.push(v);
            }
        }
        return ans;
    }
};
from collections import deque
from typing import List

class Solution:
    def minReorder(self, n: int, connections: List[List[int]]) -> int:
        g = [[] for _ in range(n)]
        for a, b in connections:
            g[a].append((b, 1))
            g[b].append((a, 0))

        vis = [False] * n
        q = deque([0])
        vis[0] = True
        ans = 0

        while q:
            u = q.popleft()
            for v, cost in g[u]:
                if vis[v]:
                    continue
                ans += cost
                vis[v] = True
                q.append(v)

        return ans
var minReorder = function(n, connections) {
  const g = Array.from({ length: n }, () => []);

  for (const [a, b] of connections) {
    g[a].push([b, 1]);
    g[b].push([a, 0]);
  }

  const vis = new Array(n).fill(false);
  const q = [0];
  vis[0] = true;
  let ans = 0;

  while (q.length) {
    const u = q.shift();
    for (const [v, cost] of g[u]) {
      if (vis[v]) continue;
      ans += cost;
      vis[v] = true;
      q.push(v);
    }
  }

  return ans;
};

中文

题目概述

给定 n 个城市和 n-1 条有向道路(无向意义下构成一棵树),要求最少反转多少条边,才能让所有城市都能到达城市 0

核心思路

把每条原始有向边 a -> b 拆成无向图中的两条可走边:a -> b 代价为 1(表示需要反转),b -> a 代价为 0(方向已正确)。从 0 出发遍历整棵树,累计代价就是最小反转次数。

算法步骤

先建带代价的邻接表,再从 0 做 BFS/DFS。
每次访问未访问过的邻居时,将对应代价加入答案并继续遍历。

复杂度分析

时间复杂度:O(n),每条边最多处理两次。
空间复杂度:O(n),用于图和 visited 数组。

常见陷阱

- 误用最短路算法,这里是树结构,一次遍历即可。
- 忘记补反向零代价边,导致计数偏大。
- 没有 visited 判断,重复计数同一条边。

多语言参考实现(Java / Go / C++ / Python / JavaScript)

class Solution {
    public int minReorder(int n, int[][] connections) {
        List<int[]>[] g = new ArrayList[n];
        for (int i = 0; i < n; i++) g[i] = new ArrayList<>();

        for (int[] e : connections) {
            int a = e[0], b = e[1];
            g[a].add(new int[]{b, 1}); // original edge a -> b, reversing needed if traversed from 0 side
            g[b].add(new int[]{a, 0}); // virtual reverse edge, no cost
        }

        int ans = 0;
        boolean[] vis = new boolean[n];
        Deque<Integer> dq = new ArrayDeque<>();
        dq.offer(0);
        vis[0] = true;

        while (!dq.isEmpty()) {
            int u = dq.poll();
            for (int[] nxt : g[u]) {
                int v = nxt[0], cost = nxt[1];
                if (vis[v]) continue;
                ans += cost;
                vis[v] = true;
                dq.offer(v);
            }
        }
        return ans;
    }
}
func minReorder(n int, connections [][]int) int {
    g := make([][][2]int, n)
    for _, e := range connections {
        a, b := e[0], e[1]
        g[a] = append(g[a], [2]int{b, 1})
        g[b] = append(g[b], [2]int{a, 0})
    }

    vis := make([]bool, n)
    q := []int{0}
    vis[0] = true
    ans := 0

    for len(q) > 0 {
        u := q[0]
        q = q[1:]
        for _, p := range g[u] {
            v, cost := p[0], p[1]
            if vis[v] {
                continue
            }
            ans += cost
            vis[v] = true
            q = append(q, v)
        }
    }

    return ans
}
class Solution {
public:
    int minReorder(int n, vector<vector<int>>& connections) {
        vector<vector<pair<int,int>>> g(n);
        for (auto& e : connections) {
            int a = e[0], b = e[1];
            g[a].push_back({b, 1});
            g[b].push_back({a, 0});
        }

        vector<int> vis(n, 0);
        queue<int> q;
        q.push(0);
        vis[0] = 1;
        int ans = 0;

        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (auto& [v, cost] : g[u]) {
                if (vis[v]) continue;
                ans += cost;
                vis[v] = 1;
                q.push(v);
            }
        }
        return ans;
    }
};
from collections import deque
from typing import List

class Solution:
    def minReorder(self, n: int, connections: List[List[int]]) -> int:
        g = [[] for _ in range(n)]
        for a, b in connections:
            g[a].append((b, 1))
            g[b].append((a, 0))

        vis = [False] * n
        q = deque([0])
        vis[0] = True
        ans = 0

        while q:
            u = q.popleft()
            for v, cost in g[u]:
                if vis[v]:
                    continue
                ans += cost
                vis[v] = True
                q.append(v)

        return ans
var minReorder = function(n, connections) {
  const g = Array.from({ length: n }, () => []);

  for (const [a, b] of connections) {
    g[a].push([b, 1]);
    g[b].push([a, 0]);
  }

  const vis = new Array(n).fill(false);
  const q = [0];
  vis[0] = true;
  let ans = 0;

  while (q.length) {
    const u = q.shift();
    for (const [v, cost] of g[u]) {
      if (vis[v]) continue;
      ans += cost;
      vis[v] = true;
      q.push(v);
    }
  }

  return ans;
};

Comments