← 返回题目列表

什么是多源 BFS?为什么可以同时从多个起点出发?

中等 第 18 / 30 题 更新于 2026/07/30
BFS多源搜索

简化版

多源 BFS 就是把多个起点同时放入队列,距离都初始化为 0,然后像普通 BFS 一样一层层扩散。

它适合求「每个点到最近源点的距离」,比如地图上每个格子到最近水源、最近腐烂橘子、最近出口的距离。

本质上,多源 BFS 等价于新建一个超级源点,用 0 权边连接所有起点,再从超级源点做 BFS。

详细版

普通 BFS 从一个起点出发,适合无权图最短路。

多源 BFS 有多个起点:

for source in sources:
  dist[source] = 0
  queue.push(source)

之后每次弹出队头,扩展邻居。如果邻居未访问,就设置距离并入队。

问题多源 BFS 含义
腐烂橘子所有腐烂橘子同时扩散
地图距离所有目标点同时作为起点
最近出口所有出口同时作为起点

它保证第一次访问到某点时,就是离任一源点的最短距离。

完整版教学

1. 普通 BFS 的最短路前提

在无权图中,BFS 按层扩展。

0 层是起点,第 1 层是一步可达节点,第 2 层是两步可达节点。

因此节点第一次被访问时,距离就是最短距离。

多源 BFS 只是把第 0 层从一个点变成多个点。

2. 多源 BFS 怎么初始化

关键是初始化队列。

queue = []
for s in sources:
  dist[s] = 0
  visited[s] = true
  queue.push(s)

所有源点同时进入队列,表示它们在时间 0 就已经存在。

多源 BFS 不是依次从每个源点跑 BFS,而是所有源点一起扩散。

3. 为什么第一次访问仍然最短

BFS 队列按层推进。

多个源点都在第 0 层,它们的邻居都在第 1 层,再往外是第 2 层。

某个节点第一次被访问时,说明从某个源点到它的距离已经是当前最小层数。其他源点如果以后再到达,只会是相同或更大的层数。

4. 超级源点怎么理解

可以想象额外增加一个虚拟节点 S

它通过权重为 0 的边连接所有源点:

S -> s1
S -> s2
S -> s3

S 出发做 BFS,就等价于把所有源点初始入队。

这个视角有助于理解为什么算法是正确的。

5. 和多次 BFS 的区别

如果有 K 个源点,每个源点都跑一次 BFS,复杂度可能是:

O(K * (V + E))

多源 BFS 只跑一次:

O(V + E)
做法复杂度是否推荐
每个源点单独 BFS源点少时勉强
多源 BFS推荐

6. 网格题怎么套

网格可以看成图。

每个格子是节点,上下左右是边。

例如腐烂橘子问题中:

  1. 把所有腐烂橘子入队;
  2. 每一层表示一分钟;
  3. 扩散到新鲜橘子时记录时间;
  4. 最后检查是否还有新鲜橘子。

这就是典型多源 BFS。

7. 适用边界是什么

多源 BFS 适合无权图,或者所有边权相同的图。

如果边权不同,就不能直接用 BFS,而要考虑多源 Dijkstra。

图类型方法
无权图多源 BFS
等权图多源 BFS
非负加权图多源 Dijkstra
有负权边Bellman-Ford 类方法

8. 常见误区与追问

  • 误区:多源 BFS 要对每个源点分别搜索。 正确做法是所有源点同时入队,只跑一次 BFS。
  • 误区:队列里多个起点会破坏最短路。 它们都属于第 0 层,BFS 层序性质仍然成立。
  • 误区:多源 BFS 可以处理任意权重。 它只适合无权或等权图。
  • 追问:怎么求每个点到最近 1 的距离? 把所有值为 1 的点入队,然后多源 BFS。
  • 追问:多源 Dijkstra 怎么做? 把多个源点距离设为 0 后一起放入优先队列。