距离上次更新已经 2011 天了,文章内容可能已经过时。

这一周的内容主要介绍了Dijkstra算法。

Course 2 Week 1

Dijkstra’s Algorithm

Dijkstra算法是解决单源最短路径问题,来看下算法的输入输出:

  • Input:有向图G=(V,E).(m=|E|,n=|V|),每条边有非负边长le,一个源点s
  • Output: 对于每个节点v,计算L(v),其中L(v)sv的最短路径长度

这里最重要的假设为le0

来看下算法描述:

解释下算法,这里将节点分为XVX,前者为已经计算完结果的节点,后者为还未计算的节点,A[s]表示到s的最短距离,B[s]记录了最短路径。

Why It Works

这部分证明为什么Dijkstra算法计算出了正确的结果,即如下事实成立:

L(v)=A[v],vV

利用数学归纳法证明。

证明:

对于出发点s,由于边长非负,所以显然有L(s)=A[s]=0,基本情形得证。

假设对于任意vXX为之前描述的已经计算的节点),L(v)=A[v],在这一轮迭代中,选择$w^ \in V-XXv\in Xv^$,那么:

B[w]=B[v]u(v,w)A[w]=A[v]+l(v,w)

现在任取一条到达$w^s\to y,y\in X,y\to z,z\in V-X,z\to w^$,如下图所示:

这里就要用到每条边都非负的假设了,由假设可得

l(z,w)0

所以

l(s,w)=l(s,y)+l(y,z)+l(z,w)l(s,y)+l(y,z)

由于$A[v^]+l(v^,w^*)sV-X$中节点的最短距离,所以

l(s,w)l(s,y)+l(y,z)A[v]+l(v,w)=A[w]

这表示

A[w]=L(w)

Fast Implementation

这一部分介绍加速算法的方法。

之前的算法一共要进行n次循环,每次要访问O(m)条边,所以算法时间复杂度为O(mn),老师介绍的方法是使用Heap,具体如下:

这里保持了两个不变量,一是堆中的元素为VX,二是每个节点的值Key[v]sv的最短路径,这样每轮循环抛出Heap顶部的即可,但是要维持第二点,还需要进行如下更新:

从上图中可以看出,之所以要进行这样的更新,是因为对于任意的点vsv的最短路径可能经过这一轮添加的节点。