双向Dijkstra算法(Bidirectional Dijkstra):有效性证明、python代码实现

Dijkstra算法能够求解无负权图(连通图、有向或无向)的单源最短路径(确定起始节点到所有其他节点的最短路径长度)

双向Dijkstra算法通过从起点(正向搜索)和终点(反向搜索)同时进行Dijkstra搜索,直到两个搜索的前沿相遇。相遇时,最短路径为正向路径与反向路径之和的最小值

  • 算法的适用条件与Dijkstra算法相同,通过减少搜索范围提升效率,尤其适用于大规模图

一、核心步骤

论文中对算法的核心步骤进行了口语化描述(Verbal description)及符号化描述(Symbolic description),本文合二为一进行描述

1.1、步骤描述

初始化:起点 s s s到各个节点的距离 S ( i ) S(i) S(i),各个节点到终点 t t t的距离 T ( i ) T(i) T(i),各个节点的上游节点 P ( i ) P(i) P(i)、各个节点的下游节点 Q ( i ) Q(i) Q(i)

步骤1:对于某个迭代过程(当前时刻),比较起点 s s s到其他节点的距离 S ( i ) S(i) S(i)与其他节点到终点 t t t的距离 T ( i ) T(i) T(i),确定需拓展的节点(若存在多个则都拓展)

  • s s s出发到节点 i i i的距离最短( M i n S ( i ) ≤ M i n T ( j ) Min S(i) \le Min T(j) MinS(i)MinT(j)),对于与 i i i相邻的节点,判断距离是否需要更新(与Dijkstra更新逻辑相同)
    • 对于 i i i的相邻节点 m m m,若 S ( m ) > d i , m + S ( i ) S(m)>d_{i,m} + S(i) S(m)>di,m+S(i),则 S ( m ) = d i , m + S ( i ) S(m)=d_{i,m} + S(i) S(m)=di,m+S(i),并且更新 m m m的上游节点为 i i i P ( m ) = i P(m)=i P(m)=i,用于确定最短路上的节点)
    • 更新从 s s s出发到其他节点的距离最短值( x = M i n S ( i ) x=Min S(i) x=MinS(i),使用 i i i标识其他节点)
  • 若节点 j j j到达 t t t的距离最短( M i n S ( i ) > M i n T ( j ) Min S(i) > Min T(j) MinS(i)>MinT(j)),对于与 j j j相邻的节点,判断距离是否需要更新
    • 对于 j j j的相邻节点 n n n,若 T ( n ) > d n , j + T ( j ) T(n)>d_{n,j} + T(j) T(n)>dn,j+T(j),则 T ( n ) > d n , j + T ( j ) T(n)>d_{n,j} + T(j) T(n)>dn,j+T(j),并且更新 n n n的下游节点为 j j j Q ( n ) = j Q(n)=j Q(n)=j,用于确定最短路上的节点)
    • 更新从其他节点到 t t t的距离最短值( y = M i n T ( j ) y=Min T(j) y=MinT(j),使用 j j j标识其他节点)

步骤2:对于某个迭代过程,比较 s s s到节点 i i i的距离与节点 i i i t t t的距离之和 S ( i ) + T ( i ) S(i)+T(i) S(i)+T(i) s s s到其他节点的距离最短值与其他节点到 t t t距离的最短值之和 M i n S ( i ) + M i n T ( i ) Min S(i)+Min T(i) MinS(i)+MinT(i)

  • M i n ( S ( i ) + T ( i ) ) ≤ M i n S ( i ) + M i n T ( i ) Min (S(i)+T(i)) \le Min S(i) + Min T(i) Min(S(i)+T(i))MinS(i)+MinT(i),则找到最短路(算法终止),根据 P ( i ) P(i) P(i) Q ( i ) Q(i) Q(i)确定完整的路径
  • 说明:
    • 不等式左侧的 S ( i ) + T ( i ) S(i)+T(i) S(i)+T(i)针对的是同一个节点 i i i,即正向( s s s到该节点)、反向(该节点到 t t t)都被搜索过的节点,意味着找到一条完整的路径 s . . . i . . . t s...i...t s...i...t
    • M i n ( S ( i ) + T ( i ) ) Min (S(i)+T(i)) Min(S(i)+T(i))即多条完整路径中距离最短的路径,可在迭代时进行更新(避免额外记录所有完整的路径)
      • s s s t t t的最短距离(完整路径)记为 μ \mu μ,迭代找到新的完整路径时,若 μ > M i n ( S ( i ) + T ( i ) ) \mu>Min (S(i)+T(i)) μ>Min(S(i)+T(i)),则 μ = M i n ( S ( i ) + T ( i ) ) \mu=Min (S(i)+T(i)) μ=Min(S(i)+T(i))
    • 不等式右侧的 S ( i ) S(i) S(i) T ( i ) T(i) T(i)只是泛指 s s s到其他节点的距离、其他节点到 t t t的距离(一般不是同一个节点)
    • M i n S ( i ) + M i n T ( i ) Min S(i) + Min T(i) MinS(i)+MinT(i)表示 s s s到其他节点的距离最短值与其他节点到 t t t距离的最短值之和

1.2、示例

在这里插入图片描述

以论文中所给的图为例进行算法步骤说明:起点1、终点9,各条边双向距离相等,例如 d 1 , 2 = d 2 , 1 = 3 d_{1,2}=d_{2,1}=3 d1,2=d2,1=3,图中 d 2 , 3 = 1 d_{2,3}=1 d2,3=1

  • ( r , x ) (r,x) (r,x)的形式进行记录,其中 r r r为节点编号, x x x为起点到节点的距离(或节点到终点的距离)
  • 对于节点1,为 ( 1 , 0 ) (1,0) (1,0),对于节点9,为 ( 9 , 0 ) (9,0) (9,0)

第1次迭代:节点1、9都需要拓展,拓展后如下图所示
在这里插入图片描述

第2次迭代: M i n S ( 2 ) > M i n T ( 6 ) = M i n T ( 8 ) Min S(2)>Min T(6)=Min T(8) MinS(2)>MinT(6)=MinT(8),节点6、8需拓展,拓展后如下图所示(节点6、8之间不连接是因为不满足更新条件)

  • 节点3、4被正向、反向搜索过,意味着找到了完整的路径,根据 P ( i ) P(i) P(i) Q ( i ) Q(i) Q(i)确定路径为1-3-6-9、1-4-7-9
  • 路径1-3-6-9长度为10,路径1-4-6-9长度为12,则 μ = 10 , x = 3 , y = 3 \mu=10, x=3, y=3 μ=10,x=3,y=3(对应节点2、5)
  • 因为 10 > 3 + 3 10>3+3 10>3+3,所以继续迭代(因为可能有更短的路径未被搜索到)
    在这里插入图片描述

第3次迭代: M i n S ( 2 ) = M i n T ( 5 ) Min S(2)=Min T(5) MinS(2)=MinT(5),节点2、5需拓展,拓展后如下图所示

  • 拓展节点2
    • 新增完整路径1-2-5-8-9,长度为10, μ = 10 \mu=10 μ=10保持不变
    • 新增完整路径1-2-3-6-9(原有路径1-3-6-9,节点3距离更新),长度为8, μ = 8 \mu=8 μ=8(距离更新)
  • 拓展节点5
    • T ( 2 ) = 7 T(2)=7 T(2)=7,无新增完整路径,, μ = 8 \mu=8 μ=8保持不变, x = 4 , y = 4 x=4, y=4 x=4,y=4(对应节点3、3)
    • 因为 8 = 4 + 4 8=4+4 8=4+4,所以迭代结束(已找到最短的路径1-2-3-6-9)
      在这里插入图片描述
      外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

二、正确性证明

只要一直迭代(章节1.2的步骤1), S ( i ) S(i) S(i) T ( i ) T(i) T(i)就会逐渐接近并达到实际的最短距离,若节点 r r r s s s t t t的最短路上,则 S ( r ) + T ( r ) S(r)+T(r) S(r)+T(r)就是最短路的长度

论文给出了明确的终止条件能够避免无谓的迭代(“早停”),需要证明 S ( r ) + T ( r ) = M i n ( S ( i ) + T ( i ) ) ≤ M i n S ( i ) + M i n T ( i ) S(r)+T(r)=Min (S(i)+T(i)) \le Min S(i) + Min T(i) S(r)+T(r)=Min(S(i)+T(i))MinS(i)+MinT(i)时,路径 s . . . r . . . t s...r...t s...r...t就是全局最短路,即其他路径的长度都不低于 S ( r ) + T ( r ) S(r)+T(r) S(r)+T(r)

为了描述证明过程,对首次满足终止条件时的关键值进行说明:

  • s s s到其他节点的最短距离为 x ′ x' x,其他节点到 t t t的最短距离为 y ′ y' y
  • 对于节点 i i i s s s i i i距离为 S ′ ( i ) S'(i) S(i) i i i t t t的距离为 T ′ ( i ) T'(i) T(i) s s s i i i的最短距离为 S ˉ ( i ) \bar{S}(i) Sˉ(i) i i i t t t的最短距离为 T ˉ ( i ) \bar{T}(i) Tˉ(i)
    • S ′ ( i ) > S ˉ ( i ) S'(i)>\bar{S}(i) S(i)>Sˉ(i),说明正向未迭代到最优,若 T ′ ( i ) > T ˉ ( i ) T'(i)>\bar{T}(i) T(i)>Tˉ(i),说明反向未迭代到最优

若能证明 S ′ ( r ) + T ′ ( r ) = M i n ( S ′ ( i ) + T ′ ( i ) ) ≤ M i n S ′ ( i ) + M i n T ′ ( i ) = x ′ + y ′ S'(r)+T'(r)=Min (S'(i)+T'(i)) \le Min S'(i) + Min T'(i)=x'+y' S(r)+T(r)=Min(S(i)+T(i))MinS(i)+MinT(i)=x+y时, S ˉ ( i ) + T ˉ ( i ) ≥ S ′ ( r ) + T ′ ( r ) \bar{S}(i)+\bar{T}(i)\ge S'(r)+T'(r) Sˉ(i)+Tˉ(i)S(r)+T(r),即说明 s . . . r . . . t s...r...t s...r...t就是全局最短路

  • 证明思路:按照 S ′ ( i ) S'(i) S(i) x ′ x' x T ′ ( i ) T'(i) T(i) y ′ y' y的大小关系划分不同情形,若不同情形下结论都成立,则结论具有完备性

2.1、case 1分析

case 1: S ′ ( i ) ≤ x ′ S'(i) \le x' S(i)x T ′ ( i ) ≤ y ′ T'(i) \le y' T(i)y

证明:

  • 对于 S ′ ( i ) ≤ x ′ S'(i)\le x' S(i)x,若之后继续迭代(假设 x ′ x' x对应的节点为 k k k),只有当 i i i k k k相邻且 S ′ ( i ) > d k , i + S ′ ( k ) = d k , i + x ′ S'(i)>d_{k,i}+S'(k)=d_{k,i}+x' S(i)>dk,i+S(k)=dk,i+x(显然不成立)时,才会更新 S ( i ) S(i) S(i)
    • 因此当 S ′ ( i ) ≤ x ′ S'(i)\le x' S(i)x时, S ( i ) S(i) S(i)不会再更新,即此时的 S ′ ( i ) = S ˉ ( i ) S'(i)=\bar{S}(i) S(i)=Sˉ(i),说明正向迭代到最优
  • 同理, T ′ ( i ) = T ˉ ( i ) T'(i)=\bar{T}(i) T(i)=Tˉ(i),说明反向迭代到最优,此时 s . . . i . . . t s...i...t s...i...t为一条完整路径
  • 因为 S ′ ( r ) + T ′ ( r ) = M i n ( S ′ ( i ) + T ′ ( i ) ) S'(r)+T'(r)=Min (S'(i)+T'(i)) S(r)+T(r)=Min(S(i)+T(i)),则 S ˉ ( i ) + T ˉ ( i ) ≥ S ′ ( r ) + T ′ ( r ) \bar{S}(i)+\bar{T}(i)\ge S'(r)+T'(r) Sˉ(i)+Tˉ(i)S(r)+T(r)核心是取了最小值(迭代时更新 s s s t t t的最短距离)
  • 结论成立

2.2、case 2分析

case 2: S ′ ( i ) > x ′ S'(i) > x' S(i)>x T ′ ( i ) > y ′ T'(i) > y' T(i)>y

证明:

  • 对于 S ′ ( i ) > x ′ S'(i)> x' S(i)>x,若之后继续迭代(假设 x ′ x' x对应的节点为 k k k),只有当 i i i k k k相邻且 S ′ ( i ) > d k , i + S ′ ( k ) = d k , i + x ′ > x ′ S'(i)>d_{k,i}+S'(k)=d_{k,i}+x'>x' S(i)>dk,i+S(k)=dk,i+x>x时,才会更新 S ( i ) S(i) S(i)
    • 不论更新与否,都满足 S ′ ( i ) > x ′ S'(i) > x' S(i)>x,因此 S ˉ ( i ) > x ′ \bar{S}(i)> x' Sˉ(i)>x
  • 同理, T ˉ ( i ) > y ′ \bar{T}(i)> y' Tˉ(i)>y
  • S ˉ ( i ) + T ˉ ( i ) > x ′ + y ′ = M i n S ′ ( i ) + M i n T ′ ( i ) ≥ S ′ ( r ) + T ′ ( r ) \bar{S}(i)+\bar{T}(i)>x'+y'=Min S'(i) + Min T'(i) \ge S'(r)+T'(r) Sˉ(i)+Tˉ(i)>x+y=MinS(i)+MinT(i)S(r)+T(r)
  • 结论成立

2.3、case 3分析

case 3: S ′ ( i ) ≤ x ′ S'(i) \le x' S(i)x T ′ ( i ) > y ′ T'(i) > y' T(i)>y

case 4: S ′ ( i ) > x ′ S'(i) > x' S(i)>x T ′ ( i ) ≤ y ′ T'(i) \le y' T(i)y

说明:case 3与case 4本质相同,因为只需要将 s s s t t t交换一下,因此只证明case 3

首先证明一个前置结论

  • 假设节点 i i i t t t的全局最短路为 P i t P_{it} Pit,其上的节点依次 b 1 , b 2 , . . . , b l b_1,b_2,...,b_l b1,b2,...,bl,其中 b 1 = i , b l = t b_1=i,b_l=t b1=i,bl=t,则一定存在一个节点 b w b_w bw 1 < w ≤ l 1<w \le l 1<wl),使 T ˉ ( b w − 1 ) > y ′ \bar{T}(b_{w-1})>y' Tˉ(bw1)>y T ˉ ( b w ) ≤ y ′ \bar{T}(b_{w}) \le y' Tˉ(bw)y,即 T ˉ ( b j ) > y ′ , 1 ≤ j ≤ w − 1 \bar{T}(b_j)> y',1 \le j \le w-1 Tˉ(bj)>y,1jw1 T ˉ ( b j ) ≤ y ′ , w ≤ j ≤ l \bar{T}(b_j)\le y',w \le j \le l Tˉ(bj)y,wjl b w b_w bw是最后一个反向迭代到最优的节点)

证明:

  • 对于 P i t P_{it} Pit上的节点 j j j T ˉ ( j ) = T ˉ ( j + 1 ) + d j , j + 1 \bar{T}(j)=\bar{T}(j+1)+d_{j,j+1} Tˉ(j)=Tˉ(j+1)+dj,j+1,因此 T ˉ ( j ) > T ˉ ( j + 1 ) \bar{T}(j)> \bar{T}(j+1) Tˉ(j)>Tˉ(j+1)(单调递减)
  • 对于节点 i i i T ′ ( i ) > y ′ T'(i) > y' T(i)>y,因此 T ˉ ( i ) > y ′ \bar{T}(i) > y' Tˉ(i)>y;对于节点 t t t T ˉ ( t ) = 0 < y ′ \bar{T}(t)=0<y' Tˉ(t)=0<y
  • 因此,一定存在一个节点 b w b_w bw 1 < w ≤ l 1<w \le l 1<wl),使 T ˉ ( b w − 1 ) > y ′ \bar{T}(b_{w-1})>y' Tˉ(bw1)>y T ˉ ( b w ) ≤ y ′ \bar{T}(b_{w}) \le y' Tˉ(bw)y
  • 结论成立

在前置结论的基础上证明 S ˉ ( i ) + T ˉ ( i ) ≥ S ′ ( r ) + T ′ ( r ) \bar{S}(i)+\bar{T}(i) \ge S'(r)+T'(r) Sˉ(i)+Tˉ(i)S(r)+T(r),考虑3种相互排斥的情形,若不同情形下结论都成立,则结论具有完备性

2.3.1、case A分析

case A:存在一个节点 b v b_v bv w ≤ v ≤ l w \le v \le l wvl), S ′ ( b v ) ≤ x ′ S'(b_v) \le x' S(bv)x

证明:

  • 对于 P i t P_{it} Pit上的节点 j j j T ˉ ( j ) = T ˉ ( j + 1 ) + d j , j + 1 \bar{T}(j)=\bar{T}(j+1)+d_{j,j+1} Tˉ(j)=Tˉ(j+1)+dj,j+1,因此 T ˉ ( b v ) = T ˉ ( i ) − ∑ k = 1 v − 1 d b k , b k + 1 \bar{T}(b_v) = \bar{T}(i) - \sum_{k=1}^{v-1}d_{b_k,b_{k+1}} Tˉ(bv)=Tˉ(i)k=1v1dbk,bk+1

  • 对于 P i t P_{it} Pit上的节点 j j j S ˉ ( j + 1 ) ≤ S ˉ ( j ) + d j , j + 1 \bar{S}(j+1) \le \bar{S}(j)+d_{j,j+1} Sˉ(j+1)Sˉ(j)+dj,j+1,因此 S ˉ ( b v ) ≤ S ˉ ( i ) + ∑ k = 1 v − 1 d b k , b k + 1 \bar{S}(b_v) \le \bar{S}(i)+\sum_{k=1}^{v-1}d_{b_k,b_{k+1}} Sˉ(bv)Sˉ(i)+k=1v1dbk,bk+1

  • S ˉ ( i ) + T ˉ ( i ) ≥ S ˉ ( b v ) − ∑ k = 1 v − 1 d b k , b k + 1 + T ˉ ( b v ) + ∑ k = 1 v − 1 d b k , b k + 1 = S ˉ ( b v ) + T ˉ ( b v ) \bar{S}(i)+\bar{T}(i) \ge \bar{S}(b_v) - \sum_{k=1}^{v-1}d_{b_k,b_{k+1}} + \bar{T}(b_v) + \sum_{k=1}^{v-1}d_{b_k,b_{k+1}} = \bar{S}(b_v) + \bar{T}(b_v) Sˉ(i)+Tˉ(i)Sˉ(bv)k=1v1dbk,bk+1+Tˉ(bv)+k=1v1dbk,bk+1=Sˉ(bv)+Tˉ(bv)

  • 此外, S ′ ( b v ) ≤ x ′ S'(b_v) \le x' S(bv)x(case 3的条件) T ˉ ( b v ) ≤ y ′ \bar{T}(b_{v}) \le y' Tˉ(bv)y(前置结论),则 S ˉ ( b v ) + T ˉ ( b v ) ≥ S ′ ( r ) + T ′ ( r ) \bar{S}(b_v)+\bar{T}(b_v) \ge S'(r)+T'(r) Sˉ(bv)+Tˉ(bv)S(r)+T(r)成立**(case 1的结论)**

  • S ˉ ( i ) + T ˉ ( i ) ≥ S ˉ ( b v ) + T ˉ ( b v ) ≥ S ′ ( r ) + T ′ ( r ) \bar{S}(i)+\bar{T}(i) \ge \bar{S}(b_v) + \bar{T}(b_v) \ge S'(r)+T'(r) Sˉ(i)+Tˉ(i)Sˉ(bv)+Tˉ(bv)S(r)+T(r)

  • 结论成立

2.3.2、case B分析

case A:存在一个节点 b v b_v bv 1 < v < w 1 < v < w 1<v<w), S ′ ( b v ) > x ′ S'(b_v) > x' S(bv)>x

证明:

  • 基于前置结论,可知 T ′ ( b j ) > T ˉ ( b j ) > y ′ , 1 ≤ j ≤ w − 1 T'(b_j)> \bar{T}(b_j) > y',1 \le j \le w-1 T(bj)>Tˉ(bj)>y,1jw1,因此 T ′ ( b v ) > y ′ T'(b_v) > y' T(bv)>y
  • 因为 S ′ ( b v ) > x ′ S'(b_v) > x' S(bv)>x T ′ ( b v ) > y ′ T'(b_v) > y' T(bv)>y,则 S ˉ ( b v ) + T ˉ ( b v ) ≥ S ′ ( r ) + T ′ ( r ) \bar{S}(b_v) + \bar{T}(b_v) \ge S'(r)+T'(r) Sˉ(bv)+Tˉ(bv)S(r)+T(r)(case 2的结论)
  • 由case A的证明过程可知, S ˉ ( i ) + T ˉ ( i ) ≥ S ˉ ( b v ) + T ˉ ( b v ) \bar{S}(i)+\bar{T}(i) \ge \bar{S}(b_v) + \bar{T}(b_v) Sˉ(i)+Tˉ(i)Sˉ(bv)+Tˉ(bv),因此 S ˉ ( i ) + T ˉ ( i ) ≥ S ′ ( r ) + T ′ ( r ) \bar{S}(i)+\bar{T}(i) \ge S'(r)+T'(r) Sˉ(i)+Tˉ(i)S(r)+T(r)
  • 结论成立

2.3.3、case C分析

case C: S ′ ( b v ) ≤ x ′ , 1 < v < w S'(b_v) \le x',1 < v < w S(bv)x,1<v<w S ′ ( b v ) > x ′ , w ≤ v ≤ l S'(b_v)> x',w \le v \le l S(bv)>x,wvl

说明:case C是case A与case B的补集(case A与case B以外的情形)

证明:

  • 由case A的证明过程可知 S ˉ ( i ) + T ˉ ( i ) ≥ S ˉ ( b w − 1 ) + T ˉ ( b w − 1 ) \bar{S}(i)+\bar{T}(i) \ge \bar{S}(b_{w-1}) + \bar{T}(b_{w-1}) Sˉ(i)+Tˉ(i)Sˉ(bw1)+Tˉ(bw1)
  • 因为 S ′ ( b v ) ≤ x ′ , 1 < v < w S'(b_v) \le x',1 < v < w S(bv)x,1<v<w,则 S ˉ ( b w − 1 ) = S ′ ( b w − 1 ) \bar{S}(b_{w-1})=S'(b_{w-1}) Sˉ(bw1)=S(bw1),因此, S ˉ ( i ) + T ˉ ( i ) ≥ S ’ ( b w − 1 ) + T ˉ ( b w − 1 ) \bar{S}(i)+\bar{T}(i) \ge S’(b_{w-1}) + \bar{T}(b_{w-1}) Sˉ(i)+Tˉ(i)S(bw1)+Tˉ(bw1)
  • 因为 T ˉ ( b w − 1 ) = T ˉ ( b w ) + d b w − 1 , b w \bar{T}(b_{w-1})=\bar{T}(b_w)+d_{b_{w-1},b_w} Tˉ(bw1)=Tˉ(bw)+dbw1,bw,则 S ˉ ( i ) + T ˉ ( i ) ≥ S ’ ( b w − 1 ) + T ˉ ( b w − 1 ) = S ’ ( b w − 1 ) + T ˉ ( b w ) + d b w − 1 , b w \bar{S}(i)+\bar{T}(i) \ge S’(b_{w-1}) + \bar{T}(b_{w-1})=S’(b_{w-1}) + \bar{T}(b_w)+d_{b_{w-1},b_w} Sˉ(i)+Tˉ(i)S(bw1)+Tˉ(bw1)=S(bw1)+Tˉ(bw)+dbw1,bw
  • 因为 T ˉ ( b w ) = T ′ ( b w ) \bar{T}(b_w)=T'(b_w) Tˉ(bw)=T(bw)(前置结论:节点 b w b_w bw已经反向收敛),则 S ˉ ( i ) + T ˉ ( i ) ≥ S ’ ( b w − 1 ) + T ′ ( b w ) + d b w − 1 , b w \bar{S}(i)+\bar{T}(i) \ge S’(b_{w-1}) + T'(b_w)+d_{b_{w-1},b_w} Sˉ(i)+Tˉ(i)S(bw1)+T(bw)+dbw1,bw
  • 因为 T ′ ( b w ) + d b w − 1 , b w ≥ T ′ ( b w − 1 ) T'(b_w)+d_{b_{w-1},b_w} \ge T'(b_{w-1}) T(bw)+dbw1,bwT(bw1)(距离更新条件),则 S ˉ ( i ) + T ˉ ( i ) ≥ S ’ ( b w − 1 ) + T ′ ( b w − 1 ) \bar{S}(i)+\bar{T}(i) \ge S’(b_{w-1}) + T'(b_{w-1}) Sˉ(i)+Tˉ(i)S(bw1)+T(bw1)
  • 若只考虑case 3的假设,则 T ′ ( b w − 1 ) > y ′ T'(b_{w-1})>y' T(bw1)>y
    • 考虑到节点 b w b_w bw已经反向收敛(节点 b w b_w bw拓展的时候会更新 T ′ ( b w − 1 ) T'(b_{w-1}) T(bw1)),因为节点 b w b_w bw b w − 1 b_{w-1} bw1都在最短路 P i t P_{it} Pit上,则此时的 T ′ ( b w − 1 ) = T ˉ ( b w − 1 ) T'(b_{w-1})=\bar{T}(b_{w-1}) T(bw1)=Tˉ(bw1)
    • 因此,节点 b w − 1 b_{w-1} bw1已经反向收敛
  • 根据case C的假设 S ′ ( b w − 1 ) ≤ x ′ S'(b_{w-1}) \le x' S(bw1)x,则 S ˉ ( i ) + T ˉ ( i ) ≥ S ’ ( b w − 1 ) + T ′ ( b w − 1 ) = S ˉ ( b w − 1 ) + T ˉ ( b w − 1 ) ≥ S ′ ( r ) + T ′ ( r ) \bar{S}(i)+\bar{T}(i) \ge S’(b_{w-1}) + T'(b_{w-1})=\bar{S}(b_{w-1})+\bar{T}(b_{w-1}) \ge S'(r)+T'(r) Sˉ(i)+Tˉ(i)S(bw1)+T(bw1)=Sˉ(bw1)+Tˉ(bw1)S(r)+T(r)
  • 结论成立

2.3.4、总结及讨论

总结(来源于DeepSeek,虽然不是很明白,但感觉很有道理 -_- )

通过路径分解和节点 b w b_w bw b v b_v bv的特性分析,Case 3的证明表明

  • 未收敛段的路径长度受限于算法终止时的队列最小值( x ′ + y ′ x'+y′ x+y
  • 收敛段的路径长度已包含在候选最短路径的比较中。
  • 因此,即使反向搜索继续优化,总路径长度 S ˉ ( i ) + T ˉ ( i ) \bar{S}(i)+\bar{T}(i) Sˉ(i)+Tˉ(i)也不会低于 S ′ ( r ) + T ′ ( r ) S'(r)+T'(r) S(r)+T(r)

遗留问题(case 3 前置结论部分)

  • 前置结论:一定存在一个节点 b w b_w bw,使 T ˉ ( b j ) > y ′ , 1 ≤ j ≤ w − 1 \bar{T}(b_j)> y',1 \le j \le w-1 Tˉ(bj)>y,1jw1 T ˉ ( b j ) ≤ y ′ , w ≤ j ≤ l \bar{T}(b_j)\le y',w \le j \le l Tˉ(bj)y,wjl
  • 论文中说可以根据前置结论得到 T ′ ( b j ) > y ′ , 1 ≤ j ≤ w − 1 T'(b_j)> y',1 \le j \le w-1 T(bj)>y,1jw1 T ′ ( b j ) ≤ y ′ , w ≤ j ≤ l T'(b_j)\le y',w \le j \le l T(bj)y,wjl
    • 因为 T ′ ( b j ) ≥ T ˉ ( b j ) T'(b_j)\ge \bar{T}(b_j) T(bj)Tˉ(bj) ,所以易得 T ′ ( b j ) > y ′ , 1 ≤ j ≤ w − 1 T'(b_j)> y',1 \le j \le w-1 T(bj)>y,1jw1
    • 对于 T ′ ( b j ) ≤ y ′ , w ≤ j ≤ l T'(b_j)\le y',w \le j \le l T(bj)y,wjl,需要证明(论文中并未使用到该结论,正确性存疑!!!)

三、示例代码

import heapq


def bidirectional_dijkstra(adj, start, end):
    # 起点到其他节点的距离
    forward_dist = {node: float('inf') for node in range(len(adj))}
    # 起点距离设置为0,放入“优先队列”
    forward_dist[start] = 0
    forward_heap = [(0, start)]
    # 各节点的上游节点
    forward_prev = {}

    reverse_dist = {node: float('inf') for node in range(len(adj))}
    reverse_dist[end] = 0
    reverse_heap = [(0, end)]
    reverse_prev = {}

    # 已搜索的节点
    visited_forward = set()
    visited_reverse = set()

    # 相遇节点及起终点间的最短距离
    meeting_node = None
    shortest_distance = float('inf')

    while forward_heap and reverse_heap:
        # 选择正向或反向队列中距离更小的节点进行扩展
        # heapq模块实现优先队列
        forward_min = forward_heap[0][0]
        reverse_min = reverse_heap[0][0]

        if forward_min <= reverse_min:
            # 正向扩展
            current_dist, u = heapq.heappop(forward_heap)
            visited_forward.add(u)
            # 更新邻接节点
            for i in range(len(adj)):
                if adj[u][i] > 0:
                    visited_forward.add(i)
                    if forward_dist[i] > forward_dist[u] + adj[u][i]:
                        forward_dist[i] = forward_dist[u] + adj[u][i]
                        heapq.heappush(forward_heap, (forward_dist[i], i))
                        forward_prev[i] = u

                    # 若相遇,计算完整路径的长度
                    if i in visited_reverse:
                        total = forward_dist[i] + reverse_dist[i]
                        # 更新最短路的长度
                        if total < shortest_distance:
                            shortest_distance = total
                            meeting_node = i

        else:
            # 反向扩展
            current_dist, u = heapq.heappop(reverse_heap)
            visited_reverse.add(u)
            for j in range(len(adj)):
                if adj[j][u] > 0:
                    visited_reverse.add(j)
                    if reverse_dist[j] > reverse_dist[u] + adj[j][u]:
                        reverse_dist[j] = reverse_dist[u] + adj[j][u]
                        heapq.heappush(reverse_heap, (reverse_dist[j], j))
                        reverse_prev[j] = u
                    if j in visited_forward:
                        total = forward_dist[j] + reverse_dist[j]
                        if total < shortest_distance:
                            shortest_distance = total
                            meeting_node = j

        # 终止条件:两队列最小键值之和 >= 当前最短路径
        if forward_heap and reverse_heap:
            current_forward_min = forward_heap[0][0]
            current_reverse_min = reverse_heap[0][0]
            if current_forward_min + current_reverse_min >= shortest_distance:
                break

    # 路径回溯:正向、反向
    if meeting_node is None:
        return None, float('inf')

    path = []
    node = meeting_node
    while node != start:
        path.append(node)
        node = forward_prev.get(node)
    path.append(start)
    path = path[::-1]

    node = meeting_node
    while node != end:
        node = reverse_prev.get(node)
        path.append(node)

    return path, shortest_distance


if __name__ == '__main__':
    # 论文中示例图的邻接矩阵
    adj = [[0, 3, 6, 7, 0, 0, 0, 0, 0],
           [3, 0, 1, 0, 4, 0, 0, 0, 0],
           [6, 1, 0, 0, 0, 2, 0, 0, 0],
           [7, 0, 0, 0, 0, 3, 4, 0, 0],
           [0, 4, 0, 0, 0, 0, 0, 1, 0],
           [0, 0, 2, 3, 0, 0, 0, 1, 2],
           [0, 0, 0, 4, 0, 0, 0, 0, 5],
           [0, 0, 0, 0, 1, 1, 0, 0, 2],
           [0, 0, 0, 0, 0, 2, 5, 2, 0]]

    path, distance = bidirectional_dijkstra(adj, 0, 8)
    print(f"最短路径: {path}")
    print(f"最短距离: {distance}")

四、相关链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值