Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

无权图的最短路径

复习

  • 广度优先搜索:第一次到达某节点即最短
  • 图:由节点和边组成
  • 队列:先进先出

TL;DR

  • 无权图中,“边数最少”就是最短
  • BFS 逐层扩张,第一次到达即最短
  • 记录每个节点的前驱,就能还原完整路径
  • 一旦边带上权重,这个结论就不再成立

正文

  图上最实用的问题之一,是“从 A 到 B 哪条路最短”。先看最简单的情形:无权图

最短就是边数最少

  在无权图里,每条边都一样“贵”,所以“路径短”只取决于经过多少条边。边数最少,就是最短。

  而我们已经有现成的工具:BFS。上一章说过,BFS 逐层扩张,第一次到达某个节点时,走过的边数就是最少的。所以,在无权图上求最短路,用 BFS 就够了。

  比如“几度人脉”——你和某人之间隔几个人,正是无权图上的最短路径问题。

顺便把路找出来

  BFS 不仅知道“有多远”,还能还原“怎么走”。

  做法是:每当我们从一个节点 u 第一次发现一个新节点 v 时,就记下“v 是从 u 来的”,也就是保存一个前驱。等 BFS 结束后,从目标节点顺着前驱一路往回找,就得到了完整路径,再反过来就是正序。

  距离用于判断,前驱用于还原。 这两样东西一起,才算真正求出了“最短路径”。

带权之后就不一样了

  可现实中,边往往不是等价的:有的路近,有的路远;有的链路快,有的慢。一旦边带上权重,“边数最少”就不再等于“代价最小”了——走两条短线,可能比走一条长线还便宜。

  这时 BFS 就无能为力了。我们需要一种能在带权图上求最短路的算法——下一章的 Dijkstra。

思考题 1

  在无权图里,为什么“边数最少”就是最短?

思考题 2

  怎样用 BFS 不仅知道距离,还能还原出具体路径?

小结

知识点

  • 无权图中,最短即边数最少
  • BFS 逐层扩张,第一次到达即最短
  • 记录前驱即可还原路径
  • 边带权重后,BFS 不再适用

参考资料

  1. Wikipedia(zh):最短路径问题:在图中寻找最优路径
  2. Wikipedia(zh):广度优先搜索:无权图最短路的基础

思考题答案(仅供参考)

思考题 1

  因为无权图中每条边的代价相同,路径的总代价只与经过的边数成正比,边数越少代价越小。所以“边数最少”就等于“最短”。

思考题 2

  在 BFS 中,每当第一次发现一个新节点时,记录它是从哪个节点到达的,即保存一个前驱指针。搜索结束后,从目标节点沿前驱一路回溯,就能得到完整路径,再将其反转即为正序。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪