算法导论(第24章 单源最短路径)

第24章 单源最短路径

问题描述

给定一个带权重的有向图\(G = (V, E)\)和权重函数\(w: E → R\),该权重函数将每条边映射到实数值的权重上(当然可能存在负权)。

图中一条路径\(p = <v_0, …, v_k>\)的权重\(w(p)\)是构成该路径的所有边的权重之和:\(w(p) = \sum_{i = 1}^{k}w(v_{i - 1}, v_i)\)

定义从结点\(u\)到结点\(v\)最短路径权重\(\delta(u, v)\)如下:

\(\delta(u, v) = min\{w(p): u → v\}\)——如果存在一条从结点\(u\)到结点\(v\)的路径

\(\delta(u, v) = \infty\)——其他

从结点\(u\)到结点\(v\)最短路径则定义为任何一条权重为\(w(p) = \delta(u, v)\)的从\(u\)\(v\)的路径\(p\)

22.2节讨论的广度优先搜索算法就是一个求取最短路径的算法,但该算法只能用于无权重的图。

最短路径的几个变体

  • 单源最短路径问题
  • 单目的地最短路径问题
  • 单结点对最短路径问题
  • 所有结点对最短路径问题

最短路径的最优子结构

最短路径算法通常依赖最短路径的一个重要性质:两个结点之间的一条最短路径包含着其他的最短路径。

而最优子结构是可以使用动态规划(第15章)和贪心算法(第16章)的一个重要指标。相应的,后面在24.3节讨论的\(Dijkstra\)算法就是一个贪心算法,在25.2节讨论的\(Floyd-Warshall\)算法则是一个动态规划算法。

  • 引理24.1(最短路径的子路径也是最短路径)

负权重的边

环路

最短路径的表示

松弛操作

最短路径和松弛操作的性质

  • 三角不等式性质

  • 上界性质

  • 非路径性质

  • 收敛性质

  • 路径松弛性质

  • 前驱子图性质

本章概要

24.1节讨论\(Bellman-Ford\)算法,该算法解决的是一般情况下的单源最短路径问题(边的权重可以为负值)。\(Bellman-Ford\)算法还能够侦测是否存在从源结点可以到达的权重为负值的环路。

24.2节给出在有向无环图中计算单源最短路径的线性时间的算法。

24.3节讨论\(Dijkstra\)算法,该算法的时间复杂度低于\(Bellman-Ford\)算法,但要求边的权重为非负值。

24.4节描述如何使用\(Bellman-Ford\)算法来解决线性规划中的一种特殊情况。

24.5节给出最短路径和松弛操作的性质的证明。

本章所讨论的所有算法都假定有向图\(G\)以邻接链表的方式予以存放。此外,边的权重与边本身存放在一起,这样在遍历每条邻接链表时,我们可以在\(O(1)\)时间内获得边的权重。

24.1 \(Bellman-Ford\)算法

\(Bellman-Ford\)算法解决的是一般情况下的单源最短路径问题,在这里,边的权重可以为负值。

给定带权重的有向图\(G = (V, E)\)和权重函数\(w: E → R\)\(Bellman-Ford\)算法返回一个布尔值,以表明是否存在一个从源结点可以到达的权重为负值的环路。如果存在这样一个环路,算法将告诉我们不存在解决方案。如果没有这种环路存在,算法将给出最短路径和它们的权重。

\(Bellman-Ford\)算法通过对边进行松弛操作来渐近地降低从源结点\(s\)到每个结点\(v\)的最短路径的估计值\(v.d\),直到该估计值与实际的最短路径权重\(\delta(u, v)\)相同为止。

img

BELLMAN-FORD(G, w, s)
1   INITIALIZE-SINGLE-SOURCE(G, s)
2   for i = 1 to |G.V| - 1
3       for each edge(u, v) ∈ G.E
4           RELAX(u, v, w)
5   for each edge(u, v) ∈ G.E
6       if v.d > u.d + w(u, v)
7           return FALSE
8   return TRUE
  • 算法第1行对所有结点的\(d\)值和\(\pi\)值进行初始化。
  • 算法第2~4行对每条边进行\(|V| - 1\)次松弛操作。
  • 算法第5~8行检查图中是否存在权重为负值的环路并返回与之相应的布尔值。

\(Bellman-Ford\)算法的复杂度为\(O(VE)\)

24.2 有向无环图中的单源最短路径问题

24.3 \(Dijkstra\)算法

\(Dijkstra\)算法解决的是带权重的有向图上单源最短路径问题,该算法要求所有边的权重都为非负值。

\(Dijkstra\)算法在运行过程中维持的关键信息是一组结点集合\(S\)。从源结点\(s\)到该集合中每个结点之间的最短路径已经被找到。算法重复从结点集\(V - S\)中选择最短路径估计最小的结点\(u\),将\(u\)加入到集合\(S\),然后对所有从\(u\)发出的边进行松弛(这里使用一个最小优先队列\(Q\)来保存结点集合,每个结点的关键值为其\(d\)值)。

img

DIJKSTRA(G, w, s)
1   INITIALIZE-SINGLE-SOURCE(G, s)
2   S = Ø
3   Q = G.V
4   while Q ≠ Ø
5       u = EXTRACT-MIN(Q)
6       S = S ∪ {u}
7       for each vertex v ∈ G.Adj[u]
8           RELAX(u, v, w)
  • 算法第1行执行的同样是\(d\)值和\(\pi\)值进行初始化。
  • 算法第2行将集合\(S\)初始化为一个空集。
  • 算法第3行对最小优先队列\(Q\)进行初始化。(算法所维持的不变式为\(Q = V - S\)
  • 算法第4~8行从\(Q\)中抽取结点\(u\)并加入到\(S\)中,对所有从结点\(u\)发出的边\((u, v)\)进行松弛操作。

\(Dijkstra\)算法的复杂度依赖于最小优先队列的实现。

  • 如果采用数组,则复杂度为\(O(V^2)\)
  • 如果采用二叉堆,则复杂度为\(O((V + E)\lg{V})\)(若所有结点都可以从源结点到达,则该时间为\(O(E\lg{V})\))
  • 如果采用斐波那契堆,则可改善为\(O(Vlog{V} + E)\)

24.4 差分约束和最短路径

24.5 最短路径性质的证明

  • 引理24.11(上界性质) 设\(G = (V, E)\)为一个带权重的有向图,权重函数为\(w: E → R\),源结点为\(s\),该图由算法\(INITIALIZE-SINGLE-SOURCE(G, s)\)执行初始化。那么对于所有的结点\(v \in V\)\(v.d \geqslant \delta(s, v)\),并且该不等式在对图\(G\)的边进行任何次序的松弛过程中保持成立。而且一旦\(v.d\)取得其下界\(\delta(s, v)\)后,将不再发生变化。

  • 引理24.13(收敛性质) 设\(G = (V, E)\)为一个带权重的有向图,权重函数为\(w: E → R\)。设\(s \in V\)为某个源结点,\(s → u → v\)为图\(G\)中的一条最短路径,这里\(u, v \in V\)。假定图\(G\)\(INITIALIZE-SINGLE-SOURCE(G, s)\)算法进行初始化,并在这之后进行了一系列边的松弛操作,其中包括对边\((u, v)\)的松弛操作\(RELAX(u, v, w)\)。如果在对边\((u, v)\)进行松弛操作之前的任意时刻有\(u.d = \delta(s, u)\),则在该松弛操作之后的所有时刻有\(v.d = \delta(s, v)\)

证明:根据上界性质——如果在对边\((u, v)\)进行松弛前的某个时刻有\(u.d = \delta(s, u)\),则该等式在松弛操作后仍然成立。所以松弛操作之后,仍然有\(u.d = \delta(s, u)\)

根据最优子结构的性质,在对边\((u, v)\)进行松弛后,有\(v.d \leqslant u.d + w(u, v) = \delta(s, u) + w(u, v) = \delta(s, v)\)

又根据上界性质,我们有\(v.d \geqslant \delta(s, v)\)

由夹逼定理:\(v.d = \delta(s, v)\),并且该等式在此之后一直保持成立。

posted @ 2022-11-01 12:02  kirin-dev  阅读(254)  评论(0编辑  收藏  举报