算法描述

Dijkstra算法(狄杰斯特拉算法):
一种基于广度优先搜索和贪婪思想的求解 无负边有向赋权图单源最短路径 的算法。
算法将所有顶点区分为「到源点 ss 的最短距离」(以后简称「距离」) 已确定 和 未确定 的顶点。算法开始前所有顶点的距离均未确定(一般置为InfinityInfinity),初始时置 ss 的距离为 0。以一个while循环查询当前 是否有距离未确定 的顶点,若有则将其中距离最小者 vv 选为 当前顶点,并使其距离已知。然后以BFS的方式松弛 vv 的邻接顶点 ww 并更新 ww 的前驱为 vv。当不再有未确定距离的顶点时算法结束,此时每一个顶点的距离均最小。通过递归寻找节点的前驱可以得到 ss 到该顶点的具体的最短路径。

松弛操作 是最短路径算法的关键,在确定当前顶点 vv (最新成为已确定距离的顶点) 后立即操作,目的是更新 vv 的邻接顶点 ww 的距离和其前驱。如下图,ss 经过若干个顶点到 aa 和 bb,aa 和 bb 邻接 cc。假设此时 dw=Inifinitydw = Inifinity,da=5da = 5,db=10db = 10。

aa 先于 bb 成为当前顶点,由于 da+∣(a,w)∣=15<Infinityda + |(a, w)| = 15 < Infinity,故 aa 松弛 dwdw,并将 ww 的前驱置为 aa,w.pre=aw.pre = a。

bb 成为当前顶点时,由于 db+∣(b,w)∣=11<15db + |(b, w)| = 11 < 15,故 bb 松弛 dwdw,并将 ww 的前驱置为 bb,w.pre=bw.pre = b。

一个直观的观察是,来自 ww 入边的松弛,使得 dwdw 不断更新至所有可能的路径距离的最小值。以下严格证明该算法正确性。


算法正确性证明

利用数学归纳法(结合反证法)证明。

本证明参考了这个帖子。

a) 数学归纳法的证明过程

  1. 起始验证。对于命题 P(n)P(n),当 n=1n = 1 时命题 PP 成立。

  2. 假设命题成立。假设命题 P(n)P(n) 在 n=m(m>1,m∈N)n = m (m > 1, m ∈ N) 时成立。

  3. 递推证明。根据2的假设,若能证明 n=m+1n = m + 1 时命题 PP 成立,则命题得证。

例如,有命题 P:1+2+3...+n=n∗(n+1)/2P:1+2+3...+n = n*(n+1)/2,按照数学归纳法证明如下:

  1. 起始验证。当 nn 等于 11 时,1=1∗(1+1)/21 = 1*(1+1)/2,命题成立。

  2. 假设命题成立。假设命题等于 mm 时成立,1+2+3+...+m=m∗(m+1)/21+2+3+...+m = m*(m+1)/2。

  3. 递推证明。根据2的假设,如果能证明 n=m+1n = m+1 时命题正确,则命题 PP 成立。

    证明:在2所示式子左右两边加上 m+1m+1,得到 1+2+3+...+m+(m+1)=m∗(m+1)/2+(m+1)1+2+3+...+m+(m+1) = m*(m+1)/2 + (m+1)

    等号右边可以写成 (m+1)∗(m+2)/2(m+1)*(m+2)/2,显然该形式就是将 n=m+1n = m+1代入原命题 PP 的形式,证毕。


b) 证明Dijkstra算法的正确性

命题 PP:Dijkstra算法第 nn 次进入while时,会将第 nn 个顶点加入距离已确定顶点集合 AA 中,此时对于顶点 ∀v∈A(∀v ∈ A(共 nn 个),总有 dv=δvdv = δv。

※ dvdv 表示由Dijkstra算法得到的最短距离估计,对于源点 ss ,在程序开始时赋予 ds=0ds = 0,对于其他顶点,由松弛操作得到。δvδv 表示实际的顶点 vv 到源点的最短距离。

  1. 起始验证。当 nn 等于 11 时,AA 集合中只有源点 ss 自身,ds=0ds = 0 (程序开始时赋值得到),且知 δv=0δv = 0,故 n=1n=1 时命题正确。

  2. 假设命题成立。假设命题 PP 在 nn 等于 mm 时,P(m)P(m) 成立,即算法经过 mm 次while,得到具有 mm 个顶点的集合 AA,对于顶点 ∀v∈A∀v ∈ A (共 mm 个),总有 dv=δvdv = δv。

  3. P(m+1)P(m+1) 递推证明。根据 2 的假设,如果能证明第 m+1m+1 个顶点 uu 被放入集合 AA 时有 du=δudu = δu,则命题 PP 成立。

    更详细地,∣A∣=m|A| = m 时,在点集 B(B=S−A)B (B = S - A) 中根据算法规则找到距离最短的顶点 uu,将该顶点将作为第 m+1m+1 个顶点放入A中,放入后 ∣A∣=m+1|A| = m + 1,如果能证明 du=δudu = δu,使得 P(m+1)P(m+1) 成立,则对于顶点 ∀v∈A∀v ∈ A (共 m+1m+1 个),有 dv=δvdv = δv。

    以反证法证明之。


    3.1 🤔 假设 m+1m+1 时 du=δudu = δu 不成立,即有如下式(1), 之后的目标是 根据已知条件导出某种矛盾情形,推翻该假设。

    (1) δu<duδu < du

    ※ δuδu 是实际的 uu 到源点的最短距离,du=δudu = δu 不成立时只能是 δu<duδu < du。算法保证了从 ss 到 uu 的过程一定是一条由图中的有向边构成的 连续路径,只要是连续路径,无论有多少条这样的路径,一定有一条最短路径,其长度记作 δuδu。并使得其他路径长度必大于等于 δu。δu。


    3.2 🤔 根据3.1的假设,存在一条从源点 ss 到 uu 的路径 PuPu,该路径是 ss 到 uu 的最短路径,即 ∣Pu∣=δu<du|Pu| = δu < du。路径 PuPu 一定有不在 AA 集内的顶点 (至少有 uu 不在 AA 集中,注意此时 uu 还未被选入 AA 中),同时也有在 AA 集中的点 (至少有 ss 点在 AA 集中),可以假设 PuPu 经过 xx 和 yy,其中 xx 在A中 (可以是 ss),yy 在B中 (可以是 uu 本身),yy 到 uu 的过程中也可以再进入 AA,如下图。PxPx 为 PuPu 在顶点 xx 结束的子路径,因为路径 Px+(x,y)Px + (x, y) 为路径 PuPu 的一部分,所以有:

    (2) ∣Px∣+∣(x,y)∣≤∣Pu∣=δu|Px| + |(x, y)| ≤ |Pu| = δu

    这是显然的,因为 Px+(x,y)Px + (x, y) 是 PuPu 的一部分,当 y=uy=u 时取到等号。



    3.3 🤔 在 xx 之前被选中进入 AA 集内时,对其邻接顶点 yy 执行过 松弛操作,该操作会比较 dx+∣(x,y)∣dx + |(x, y)| 是否小于 dydy,若小于则以 dx+∣(x,y)∣dx + |(x, y)| 更新 dydy 的值,所以如果更新了,更新之后有 dy=dx+∣(x,y)∣dy = dx + |(x, y)| ,如果没更新,说明 dy<dx+∣(x,y)∣dy < dx + |(x, y)|。假设之后 yy 还会被 yy 的其他前驱顶点更新 dydy 值 (当该前驱顶点进入 AA 集时),那 dydy 只会变得更小,所以一定有:

    (3) dy≤dx+∣(x,y)∣dy ≤ dx + |(x, y)|

    比较式 (2) 和式 (3) 中的 ∣Px∣|Px| 和 dxdx,因为 dx=δxdx = δx (由步骤2的 P(m)P(m) 假设给出,顶点 xx 是 P(m)P(m) 假设的 mm 个顶点之一),而 PxPx 只是若干从 ss 到 xx 的路径之一,因此必有 d(x)≤∣Px∣d(x) ≤ |Px|,当 PxPx 恰是 ss 到 xx 的最短路径时取到等号。所以根据式 (2) 和式 (3) 有:

    dy≤dx+∣(x,y)∣≤∣Px∣+∣(x,y)∣≤∣Pu∣dy ≤ dx + |(x, y)| ≤ |Px| + |(x, y)| ≤ |Pu|,即

    (4) dy≤∣Pu∣=δudy ≤ |Pu| = δu

    3.4 🤔 顶点 yy 与 uu 均在 BB 集中,根据算法规则,uu 作为第 m+1m+1 个定点被放入 AA 集中时,其在 BB 集中相比于BB 集中的其他顶点(自然也包括 yy ),到源点 ss 的距离最小,显然有:

    (5) du≤dydu ≤ dy

    结合式 (1),式 (4),式 (5)得到:

    (6) δu<du≤dy≤∣Pu∣=δuδu < du ≤ dy ≤ |Pu| = δu ,即 δu<δuδu < δu

至此,由3.1的假设 「d(u)=δ(u)d(u) = δ(u) 不成立」导出了 矛盾,所以 d(u)=δ(u)d(u) = δ(u) 是成立的,Dijkstra算法正确性得证。