题目
n 座城市,从 0 到 n-1 编号,其间共有 n-1 条路线。因此,要想在两座不同城市之间旅行只有唯一一条路线可供选择(路线网形成一颗树)。去年,交通运输部决定重新规划路线,以改变交通拥堵的状况。
路线用 connections 表示,其中 connections[i] = [a, b] 表示从城市 a 到 b 的一条有向路线。
今年,城市 0 将会举办一场大型比赛,很多游客都想前往城市 0 。
请你帮助重新规划路线方向,使每个城市都可以访问城市 0 。返回需要变更方向的最小路线数。
题目数据 保证 每个城市在重新规划路线方向后都能到达城市 0 。
一、代码实现(BFS邻接表法)
go
func minReorder(n int, connections [][]int) int {
adj := make([][][2]int, n) // [邻接节点,方向标记]
for _, conn := range connections {
a, b := conn[0], conn[1]
adj[a] = append(adj[a], [2]int{b, 1}) // 原始边a→b标记为1(需反转)
adj[b] = append(adj[b], [2]int{a, 0}) // 反向边b→a标记为0(无需反转)
}
visited := make([]bool, n)
queue := []int{0}
visited[0] = true
count := 0
for len(queue) > 0 {
u := queue[0]
queue = queue[1:]
for _, vPair := range adj[u] {
v, dir := vPair[0], vPair[1]
if !visited[v] {
visited[v] = true
queue = append(queue, v)
count += dir // 方向标记为1的边需要反转
}
}
}
return count
}
二、算法分析
1. 核心思路
- 逆向树构建:以城市0为根构建逆向树,正确方向应为子节点→父节点
- 邻接表标记:每条边记录原始方向,正向边标记1(需反转),反向边标记0
- 广度优先遍历:从城市0出发逐层处理,累计方向标记为1的边数量
2. 关键步骤
- 邻接表初始化:为每个节点存储邻接关系和方向标记(15-19行)
- BFS队列初始化:从根节点0开始遍历(22-23行)
- 方向判断逻辑:遇到标记为1的边需计入调整次数(30行)
- 防重复处理:使用visited数组避免重复访问(26行条件判断)
3. 复杂度
指标 | 值 | 说明 |
---|---|---|
时间复杂度 | O(n) | 每个节点和边仅访问一次 |
空间复杂度 | O(n) | 邻接表存储n节点+n-1边信息 |
三、图解示例

四、边界条件与扩展
1. 特殊场景验证
- 单节点树:n=1时直接返回0(无需调整)
- 全逆向边 :如
[[1,0],[2,1],[3,2]]
返回0 - 链式结构 :
0←1←2←3
若原边全正向需反转3次
2. 扩展应用
- 动态网络更新:支持实时添加/删除边后快速计算
- 多目标优化:结合交通流量、排放等多因素决策
- 区域交通网络:扩展到公路、铁路多模式网络
五、多语言实现
python
from collections import deque
def minReorder(n: int, connections: list) -> int:
graph = [[] for _ in range(n)]
for a, b in connections:
graph[a].append((b, 1)) # 正向边
graph[b].append((a, 0)) # 反向边
visited = [False]*n
q = deque([0])
visited[0] = True
res = 0
while q:
u = q.popleft()
for v, dir in graph[u]:
if not visited[v]:
visited[v] = True
q.append(v)
res += dir
return res
java
class Solution {
public int minReorder(int n, int[][] connections) {
List<List<int[]>> adj = new ArrayList<>();
for (int i = 0; i < n; i++)
adj.add(new ArrayList<>());
for (int[] conn : connections) {
adj.get(conn[0]).add(new int[]{conn[1], 1});
adj.get(conn[1]).add(new int[]{conn[0], 0});
}
boolean[] visited = new boolean[n];
Queue<Integer> queue = new LinkedList<>();
queue.offer(0);
visited[0] = true;
int count = 0;
while (!queue.isEmpty()) {
int u = queue.poll();
for (int[] vPair : adj.get(u)) {
int v = vPair[0], dir = vPair[1];
if (!visited[v]) {
visited[v] = true;
queue.offer(v);
count += dir;
}
}
}
return count;
}
}
六、总结与优化
1. 核心创新点
- 逆向树遍历 :通过反向构建树形结构确保连通性[^- 方向标记法:用0/1区分原始边方向实现快速判断
- 线性时间复杂度:BFS/DFS均实现O(n)高效计算
2. 工程优化方向
- 并行计算:子树分块处理加速大规模网络
- 内存压缩:用位运算替代二维数组存储方向
- 实时预测:结合交通流量预测动态调整
3. 算法扩展
- 多式联运网络:整合公路、铁路、航空多模式交通
- 故障容错机制:保证单边故障时的连通性
- 智能交通系统:与信号灯控制、路径规划联动优化