文章目录

  • 0 前言
    • 0.1 最短路径的几个变体
    • 0.2 最短路径的最优子结构
    • 0.3 负权重的边
    • 0.4 环路
    • 0.5 最短路径的表示
    • 0.6 松弛操作
    • 0.7 最短路径和松弛操作的性质
  • 1 Bellman-Ford算法
  • 2 有向无环图中的单源最短路径问题
  • 3 Dijkstra算法
  • 4 差分约束和最短路径
  • 5 最短路径性质的证明

0 前言

在最短路径问题中,给定一个带权重的有向图G=(V,E)和权重函数w:E→R,该权重函数将每条边映射到实数值的权重上。图中一条路径p=<v0,v1,…,vk>的权重w(p)是构成该路径的所有边的权重之和:

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

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

广度优先搜索算法就是一个可以用来求取最短路径的算法,但该算法只能用于无权重的图,即每条边的权重都是1的图。

0.1 最短路径的几个变体

单源最短路径问题:给定一个图G=(V,E),希望找到从给定源结点s∈V到每个结点v∈V的最短路径。解决单源最短路径问题的思想可以用来解决下面的几个最短路径的变体问题:

1、单目的地最短路径问题:找到从每个结点v到给定目的地结点t的最短路径。如果将图的每条边的方向翻转过来,就可以将这个问题转换为单源最短路径问题。

2、单结点对最短路径问题:找到从给定结点u到给定结点v的最短路径。如果解决了针对单个结点u的单源最短路径问题,那么也就解决了这个问题。

3、所有结点对最短路径问题:对于每对结点u和v,找到从结点u到结点v的最短路径。虽然可以针对每个结点运行一遍单源最短路径算法,但通常可以更快地解决这个问题,将在下一篇博文中讨论此问题。

0.2 最短路径的最优子结构

最短路径算法通常依赖最短路径的一个重要性质:两个结点之间的一条最短路径包含着其他的最短路径。下面的引理精确地叙述了最短路径的最优子结构性质。

引理1:(最短路径的子路径也是最短路径)给定带权重的有向图G=(V,E)和权重函数w:E→R。设p=<v0,v1,…,vk>为从结点v0到结点vk的一条最短路径,并且对于任意的i和j,0≤i≤j≤k,设pij=<vi,vi+1,…,vj>为路径p中从结点vi到结点vj的子路径。那么pij是从结点vi到结点vj的一条最短路径。

证明

引理1得证

0.3 负权重的边

某些单源最短路径问题可能包括权重为负值的边。但如果图G=(V,E)不包含从源结点s可以到达的权重为负值的环路,则对于所有的结点v∈V,最短路径权重δ(s,v)都有精确定义,即使其取值是负数。

如果图G包含从s可以达到的权重为负值的环路,则最短路径权重无定义。从s到该环路上的任意结点的路径都不可能是最短路径,因为只要沿着任何“最短”路径再遍历一次权重为负值的环路,则总是可以找到一条权重更小的路径。如果从结点s到结点v的某条路径上存在权重为负值的环路,定义δ(s,v)=-∞。

上图(记为图1)描述的是负权重和权重为负值的环路对最短路径权重的影响。从源点s到其他各结点的最短路径及长度分析如下:

1、δ(s,a)=w(s,a)=3,因为从结点s到结点a只有一条路径(路径<s,a>)。

2、δ(s,b)=w(s,a)+w(a,b)=3+(-4)=-1,因为从结点s到结点b也只有一条路径。

3、从结点s到结点c则有无数条路径:<s,c>,<s,c,d,c>,<s,c,d,c,d,c>等。因为环路<c,d,c>的权重为6+(-3)=3>0,因此从结点s到结点c的最短路径是<s,c>,其权重为δ(s,c)=w(s,c)=5。

4、δ(s,d)=w(s,c)+w(c,d)=11,因为从结点s到结点d的最短路径为<s,c,d>。

5、从结点s到结点e也有无数条路径:<s,e>,<s,e,f,e>,<s,e,f,e,f,e>等。因为环路<e,f,e>的权重为3+(-6)=-3<0,因此从结点s到结点e没有最短路径。通过遍历负权重环路<e,f,e>任意次数,可以找到权重为任意负值的从结点s到结点e的路径,因此δ(s,e)=-∞。类似地,δ(s,f)=-∞。

6、δ(s,g)=-∞。因为结点g可以从结点f到达,因此可以找到一条权重为任意负值的从结点s到结点g的路径。

7、虽然结点h、i和j也形成一个权重为负值的环路,但它们不能从结点s到达,因此δ(s,h)=δ(s,i)=δ(s,j)=∞。

某些最短路径算法(如Dijkstra算法)假设输入图的所有的边权重为非负值;而另外一些算法(如Bellman-Ford算法)允许输入图中包含负权重的边,但只要没有可以从源结点到达的权重为负值的环路,就可以生成正确的答案。

0.4 环路

一条最短路径不能包含权重为负值的环路,也不能包含权重为正值的环路,因为只要将环路从路径上删除就可以得到一条源结点和终结点与原来路径相同的一条权重更小的路径。也就是说,如果p=<v0,v1,…,vk>是一条路径,c=<vi,vi+1,…,vj>是该路径上的一条权重为正值的环路(因此vi=vj并且w(c)>0),则路径p’=<v0,v1,…,vi,vj+1,vj+2,…,vk>的权重w(p')=w(p)-w(c)<w(p),因此p不可能是从v0到vk的一条最短路径。

这样就只剩下权重为0的环路。

由于可以从任何路径上删除权重为0的环路而得到另一条权重相同的路径,因此如果从源结点s到终结点v存在一条包含权重为0的环路的最短路径,则也同时存在另一条不包含该环路的从结点s到结点v的最短路径。只要一条最短路径上还有权重为0的环路,就可以重复删除这些环路,直到得到一条不包括环路的最短路径。

不失一般性地,可以假定在找到的最短路径中没有环路,即它们都是简单路径。由于图G=(V,E)中的任意无环路径最多包含|V|个不同的结点,它也最多包含|V|-1条边,因此可以将注意力集中到至多只包含|V|-1条边的最短路径上。

0.5 最短路径的表示

待解决的问题要求计算出最短路径权重和最短路径上的结点。

给定图G=(V,E),对于每个结点v,维持一个前驱结点v.π,该前驱结点可能是另一个结点或者NIL。若对每个结点的π属性进行设置,则将从结点v开始的前驱结点链反转过来,就是从s到v的一条最短路径。但在运行最短路径算法的过程中,π值并不一定能给出最短路径。

定义由π值所诱导的前驱子图Gπ=(Vπ,Eπ),结点集Vπ为图G中的前驱结点不为NIL的结点的集合,再加上源结点s,即:

Vπ={v∈V:v.π≠NIL}∪{s}

有向边集合Eπ是由Vπ中的结点的π值所诱导的边的集合,即:

Eπ={(v.π,v)∈E:v∈Vπ-{s}}

本博文的算法所生成的π值具有如下性质:在算法终止时,Gπ是一棵“最短路径树”,它是一棵有根结点的树,该树包括了从源结点s到每个可以从s到达的结点的一条最短路径。

设G=(V,E)是一条带权重的有向图,其权重函数为w:E→R,假定G不包含从s可以到达的权重为负值的环路,因此所有的最短路径都有定义。一棵根结点为s的最短路径树是一个有向子图G’=(V’,E’),这里V’⊆V,E’⊆E,满足:

1、V’是图G中从源结点s可以到达的所有结点的集合。

2、G’形成一棵根结点为s的树。

3、对于所有的结点v∈V’,图G’中从结点s到结点v的唯一简单路径是图G中从结点s到结点v的一条最短路径。

最短路径不一定是唯一的,最短路径树也不一定是唯一的。下图(记为图2)描述的是一个带权重的有向图和两棵根结点相同的最短路径树:

0.6 松弛操作

本博文的算法需要使用松弛(relaxation)技术。对于每个结点v来说,维持一个属性v.d,用来记录从源结点s到结点v的最短路径权重的上界,称v.d为s到v的最短路径估计。

使用下面运行时间为Θ(V)的算法来对最短路径估计和前驱结点进行初始化:

INITIALIZE-SINGLE-SOURCE(G,s)for each vertex v∈G.Vv.d=∞v.π=NILs.d=0

在初始化操作结束后,对于所有的结点v∈V,有v.π=NIL,且s.d=0,对于所有的结点v∈V-{s},有v.d=∞。

对一条边的(u,v)的松弛过程为:首先测试一下是否可以对从s到v的最短路径进行改善——将从结点s到结点u之间的最短路径距离加上结点u与v之间的边权重,并与当前的s到v的最短路径估计进行比较,如果前者更小,则对v.d和v.π进行更新。松弛步骤可能降低最短路径的估计值v.d并更新v的前驱属性v.π。下面的伪代码执行的就是对边(u,v)在O(1)时间内进行的松弛操作:

RELAX(u,v,w)if v.d>u.d+w(u,v)v.d=u.d+w(u,v)v.π=u

下图(记为图3)描述的是对一条边进行松弛的两个例子:

在上图左面的例子中,最短路径估计因松弛操作而减少了;在右面的例子中,最短路径估计则没有发生变化。

本博文后面的每个算法都将调用算法INITIALIZE-SINGLE-SOURCE,然后重复对边进行RELAX松弛,且松弛是唯一导致最短路径估计和前驱结点发生变化的操作。本博文所讨论的所有算法之间的不同之处是对每条边进行松弛的次数和松弛边的次序有所不同。Dijkstra算法和用于有向无环图的最短路径算法对每条边仅松弛一次,而Bellman-Ford算法则对每条边松弛|V|-1次。

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

为了证明本博文所讨论算法的正确性,需要使用最短路径和松弛操作如下的一些性质,其中后面5条性质都涉及最短路径估计或前驱子图,它们成立的前提是必须调用INITIALIZE-SINGLE-SOURCE(G,s)来对图进行初始化,并且所有对最短路径估计和前驱子图所进行的改变都是通过一系列的松弛步骤来实现的:

1、三角不等式性质:对于任何边(u,v)∈E,有δ(s,v)≤δ(s,u)+w(u,v)。

2、上界性质:对于所有的结点v∈V,总是有v.d≥δ(s,v),且一旦v.d的取值达到δ(s,v),其值将不再发生变化。

3、非路径性质:如果从结点s到结点v之间不存在路径,则总是有v.d=δ(s,v)=∞。

4、收敛性质:对于某些结点u,v∈V,如果s→u→v是图G中的一条最短路径,并且在对边(u,v)进行松弛前的任意时间有u.d=δ(s,u),则在之后的所有时间有v.d=δ(s,v)。

5、路径松弛性质:如果p=<v0,v1,…,vk>是从源结点s=v0到结点vk的一条最短路径,则规定对p中的边所进行松弛的次序为(v0,v1),(v1,v2),…,(vk-1,vk),且有vk.d=δ(s,vk)。

6、前驱子图性质:对于所有的结点v∈V,一旦v.d=δ(s,v),则前驱子图是一棵根结点为s的最短路径树。

后面将讨论的Bellman-Ford算法解决的是一般情况下的单源最短路径问题,即边的权重可以为负值,并且它还能够侦测是否存在从源结点可以到达的权重为负值的环路。之后将给出在有向无环图中计算单源最短路径的线性时间的算法。最后讨论Dijkstra算法,该算法的时间复杂度低于Bellman-Ford算法,但要求边的权重必须为非负值。

规定:

1、对于任意实数a≠-∞,有a+∞=∞+a=∞。

2、对于任意实数a≠∞,有a+(-∞)=(-∞)+a=-∞。

本博文所讨论的所有算法都假定有向图G以邻接链表的方式进行存储,且边的权重与边本身存放在一起,这样在遍历每条邻接链表时,可以在O(1)时间内获得边的权重。


1 Bellman-Ford算法

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

Bellman-Ford算法通过对边进行松弛操作来渐近地降低从源结点s到每个结点v的最短路径的估计值v.d,直到该估计值与实际的最短路径权重δ(s,v)相同时为止。该算法返回TRUE值当且仅当输入图不包含可以从源结点到达的权重为负值的环路。

BELLMAN-FORD(G,w,s)INITIALIZE-SINGLE-SOURCE(G,s)for i=1 to |G.V|-1for each edge(u,v)∈G.ERELAX(u,v,w)for each edge(u,v)∈G.Eif v.d>u.d+w(u,v)return FALSEreturn TRUE


上图(记为图4)描述的是在有5个结点的图上运行Bellman-Ford算法的过程。在算法第2行对所有结点的d值和π值进行初始化后,算法对图的每条边进行|V|-1次处理。每一次处理对应的是算法第3-5行for循环的一次循环,该循环对图的每条边进行一次松弛操作。图4(b)-(e)描述的是对边进行4次松弛操作时,每一次松弛后的算法状态。在进行了|V|-1次松弛操作后,算法第6-9行负责检查图中是否存在权重为负值的环路并返回与之相适应的布尔值。

由于算法第2行的初始化操作所需时间为Θ(V),第3-5行循环的运行时间为Θ(E),且一共要进行|V|-1次循环,而第6-8行的for循环所需时间为O(E),因此Bellman-Ford算法的总运行时间为O(V·E)。

要证明Bellman-Ford算法的正确性,首先需要证明在没有权重为负值的环路的情况下,该算法可以正确计算出从源结点可以到达的所有结点之间的最短路径权重。

引理2:设G=(V,E)为一个带权重的源结点为s的有向图,其权重函数为w:E→R。假定图G不包含从源结点s可以到达的权重为负值的环路。那么在算法BELLMAN-FORD的第3-5行的for循环执行了|V|-1次之后,对于所有从源结点s可以到达的结点v,有v.d=δ(s,v)。

证明:通过使用路径松弛性质来证明本引理。考虑任意从源结点s可以到达的结点v,设p=<v0,v1,…,vk>为从源结点s到结点v之间的任意一条最短路径,这里v0=s,vk=v。因为最短路径都是简单路径,p最多包含|V|-1条边,因此k≤|V|-1。算法第3-5行的for循环每次松弛所有的|E|条边。在第i次松弛操作时,这里i=1,2,…,k,被松弛的边中包含边(vi-1,vi)。根据路径松弛性质可得:v.d=vk.d=δ(s,vk)=δ(s,v)。

引理2得证

推论3(这里不列出证明过程):设G=(V,E)是带权重的源结点为s的有向图,其权重函数为w:E→R。假定图G不包含从源结点s可以到达的权重为负值的环路,则对于所有结点v∈V,存在一条从源结点s到结点v的路径当且仅当BELLMAN-FORD算法终止时有v.d<∞。

定理4:(Bellman-Ford算法的正确性)设BELLMAN-FORD算法运行在带权重的源结点为s的有向图G=(V,E)上,该图的权重函数为w:E→R。如果图G不包含从源结点s可以到达的权重为负值的环路,则算法将返回TRUE值,且对于所有结点v∈V,前驱子图Gπ是一棵根结点为s的最短路径树。如果图G包含一条从源结点s可以到达的权重为负值的环路,则算法将返回FALSE值。

证明:假定图G不包含从源结点s可以到达的权重为负值的环路。首先证明,对于所有结点v∈V,在算法BELLMAN-FORD终止时,有v.d=δ(s,v)。如果结点v是从s可以到达的,则引理2证明了本论断。如果结点v不能从s到达,则该论断可以从非路径性质获得。因此,该论断得到证明。综合前驱子图性质和本论断可以推导出Gπ是一棵最短路径树。现在,使用这个论断来证明BELLMAN-FORD算法返回的是TRUE值。在算法BELLMAN-FORD终止时,对于所有的边(u,v)∈E,有:

因此,算法第7行中没有任何测试可以让BELLMAN-FORD算法返回FALSE值。因此,它一定返回的是TRUE值。

现在假定图G包含一个权重为负值的环路,并且该环路可以从源结点s到达;设该环路为c=<v0,v1,…,vk>,这里v0=vk,则有:

下面使用反证法证明上图的式子。

假设Bellman-Ford算法返回的是TRUE值,则vi.d≤vi-1.d+w(vi-1,vi),这里i=1,2,…,k。将环路c上的所有这种不等式加起来,有:

由于v0=vk,环路c上面的每个结点在下面的求和表达式:

中刚好各出现一次,因此有:

而且,根据推论3,vi.d对于i=1,2,…,k来说取的都是有限值,因此有:

而这与

矛盾。因此,如果图G不包含从源结点s可以到达的权重为负值的环路,则Bellman-Ford算法返回TRUE值,否则返回FALSE值。

定理4得证


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

Directed Acyclic Graph,DAG,有向无环图。

根据结点的拓扑排序次序来对带权重的有向无环图G=(V,E)进行边的松弛操作,便可以在Θ(V+E)时间内计算出从单个源结点到所有结点之间的最短路径。在有向无环图中,即使存在权重为负值的边,但因为没有权重为负值的环路,最短路径都是存在的。

下面的算法先对有向无环图进行拓扑排序,以便确定结点之间的一个线性次序。如果有向无环图包含从结点u到结点v的一条路径,则u在拓扑排序的次序中位于结点v的前面。只需要按照拓扑排序的次序对结点进行一遍处理即可。每次对一个结点进行处理时,对该结点的所有出边进行松弛操作。

DAG-SHORTEST-PATHS(G,w,s)topologically sort the vertices of GINITIALIZE-SINGLE-SOURCE(G,s)for each vertex u, taken in topologically sorted orderfor each vertex v∈G.Adj[u]RELAX(u,v,w)

下图(记为图5)描述的是算法DAG-SHORTEST-PATHS的执行过程:

该算法第2行的拓扑排序时间为Θ(V+E)。第3行对INITIALIZE-SINGLE-SOURCE的调用所需时间为Θ(V)。第4-6行的for循环(外循环)对于每个结点执行一遍,因此第5-6行的for循环(内循环)对每条边刚好松弛一次(这里使用了聚集分析)。因为内循环每次的运行时间为Θ(1),因此算法的总运行时间为Θ(V+E)。

下面的定理将证明DAG-SHORTEST-PATHS过程正确计算出所有的最短路径。

定理5:如果带权重无环路的有向图G=(V,E)有一个源结点s,则在算法DAG-SHORTEST-PATHS终止时,对于所有的结点v∈V,有v.d=δ(s,v),且前驱子图Gπ是一棵最短路径树。

证明:首先证明对于所有的结点v∈V,在算法DAG-SHORTEST-PATHS终止时都有v.d=δ(s,v)。如果结点v不能从源结点s到达,则根据非路径性质有v.d=δ(s,v)=∞。现在假定结点v可以从结点s到达,因此,图中存在一条最短路径p=<v0,v1,…,vk>,这里v0=s,vk=v。因为算法是按照拓扑排序的次序来对结点进行处理,所以对路径p上的边的松弛次序为(v0,v1),(v1,v2),…,(vk-1,vk)。根据路径松弛性质,对于i=0,1,…,k,在算法终止时有vi.d=δ(s,vi)。最后,根据前驱子图性质,Gπ是一棵最短路径树。

定理5得证


3 Dijkstra算法

Dijkstra算法解决的是带权重的有向图上单源最短路径问题,要求所有边的权重都为非负值。因此,在本节的讨论中,假定对于所有的边(u,v)∈E,都有w(u,v)≥0。Dijkstra算法在运行过程中维持的关键信息是一组结点集合S,其中从源结点s到该集合中每个结点之间的最短路径已经被找到。算法重复从结点集V-S中选择最短路径估计最小的结点u,将u加入到集合S,然后对所有从u发出的边进行松弛。在下面给出的实现方式中,使用一个最小优先队列Q来保存结点集合,每个结点的关键值为其d值。

DIJKSTRA(G,w,s)INITIALIZE-SINGLE-SOURCE(G,s)S=∅Q=G.Vwhile Q≠∅u=EXTRACT-MIN(Q)S=S∪{u}for each vertex v∈G.Adj[u]RELAX(u,v,w)

Dijkstra算法对边的松弛操作如下图(记为图6)所示:

算法第2行执行的是对d值和π值的初始化,第3行将集合S初始化为一个空集。算法所维持的不变式为Q=V-S,该不变式在算法第5-9行的while循环过程中保持不变。算法第4行对最小优先队列Q进行初始化,将所有的结点V都放在该队列里。由于此时的S=∅,不变式在第4行执行完毕后成立。算法在每次执行第5-9行的while循环时,第6行从Q=V-S集合中抽取结点u,第7行将该结点加入到集合S里,从而继续保持不变式成立。注意,在第一次执行该循环时u=s。结点u是集合V-S中所有结点的最小最短路径估计。然后,在算法的第8-9行,对所有从结点u发出的边(u,v)进行松弛操作。如果一条经过结点u的路径能够使得从源结点s到结点v的最短路径权重比当前的估计值更小,则对v.d的值和前驱v.π的值进行更新。注意,在算法的第4行之后,再不会在队列Q中插入任何结点,而每个结点从Q中被抽取的次数和加入集合S的次数均为一次,因此,算法第5-9行的while循环的执行次数刚好为|V|次。

因为Dijkstra算法总是选择集合V-S中“最轻”或“最近”的结点来加入到集合S中,因此该算法使用的是贪心策略。虽然贪心策略并不总是能获得最优的结果,但正如下面的定理和推论所指出的,使用贪心策略的Dijkstra算法确实能够计算出最短路径。这里的关键是证明:该算法在每次选择结点u来加入到集合S时,有u.d=δ(s,u)。

定理6:(Dijkstra算法的正确性)Dijkstra算法运行在带权重的有向图G=(V,E)时,如果所有权重为非负值,则在算法终止时,对于所有结点u∈V,有u.d=δ(s,u)。

证明:使用下面的循环不变式:

【在算法第5-9行的while语句的每次循环开始前,对于每个结点v∈S,有v.d=δ(s,v)。只需要证明对于每个结点u∈V,当结点u被加入到集合S时,有u.d=δ(s,u)。一旦证明了u.d=δ(s,u),就可以使用上界性质来证明该等式在后续的所有时间内保持成立。】

1、初始化:初始时,S=∅,因此,循环不变式直接成立。

2、保持:现在需要证明在每次循环中,对于加入到集合S的结点u来说,u.d=δ(s,u)。使用反证法来证明此论断。设结点u是第一个在加入到集合S时使得该方程式不成立的结点,即u.d≠δ(s,u)。下面将注意力集中到把结点u加入到集合S的这遍循环的开始,并通过对从结点s到结点u的最短路径进行检查来导出结论u.d=δ(s,u)。由于结点s是第一个加入到集合S中的结点,并且s.d=δ(s,s)=0,因此结点u必定与结点s不同,即u≠s。因为u≠s,在即将把结点u加入到集合S时,有S≠∅。此时,一定存在某条从结点s到结点u的路径,否则,根据非路径性质将有u.d=δ(s,u)=∞,而这将违反刚才的假设u.d≠δ(s,u)。既然至少存在一条从s到u的路径,所以也存在一条从s到u的最短路径p。在将结点u加入到集合S之前,路径p连接的是集合S中的一个结点(即s)和V-S中的一个结点(即u)。考虑路径p上第一个满足y∈V-S的结点y,设x∈S为结点y在路径p上的前驱,则如下图(记为图7)所示:

可以将路径分解为:

注意,路径p1或者p2可能不包含任何边。可以断言:在将结点u加入到集合S时,y.d=δ(s,y)。为了证明这一点,只要观察到x∈S。然后,因为选择的结点u是第一个在加入到集合S时不满足条件u.d=δ(s,u)的结点,在将结点x加入到集合S时,有x.d=δ(s,x)。此时,边(x,y)将被松弛,根据收敛性质可以得出y.d=δ(s,y)。

下面通过反证来证明u.d=δ(s,u)。因为结点y是从结点s到结点u的一条最短路径上位于u前面的一个结点,并且所有的边权重均为非负值,所以有δ(s,y)≤δ(s,u),因此:

又因为在算法第6行选择结点u时,结点u和y都在集合V-S里,所以有u.d≤y.d。因此,上图中的两个不等式事实上都是等式,即y.d=δ(s,y)=δ(s,u)=u.d。因此u.d=δ(s,u),而这与所选择的结点u矛盾。因此在结点u被加入到集合S时有u.d=δ(s,u),并且该等式在随后的所有时间内都保持成立。

3、终止:在算法终止时,Q=∅。该事实与之前的不变式Q=V-S一起说明了S=V。因此,对于所有的结点u∈V,有u.d=δ(s,u)。

定理6得证

推论7:如果在带权重的有向图G=(V,E)上运行Dijkstra算法,其中的权重皆为非负值,源结点为s,则在算法终止时,前驱子图Gπ是一棵根结点为s的最短路径树。

证明:从定理6和前驱子图性质可立即得知该推论。

推论7得证

Dijkstra算法执行三种优先队列操作来维持最小优先队列:INSERT(算法第4行所隐含的操作)、EXTRACT-MIN(算法第6行)和DECREASE-KEY(隐含在算法第9行所调用的RELAX操作中)。该算法对每个结点调用一次INSERT和EXTRACT-MIN操作。因为每个结点仅被加入到集合S一次,因此邻接链表Adj[u]中的每条边在整个算法运行期间也只被检查一次(在算法第8-9行的for循环里)。由于所有邻接链表中的边的总数为|E|,于是该for循环的执行次数一共为|E|次,因此该算法调用DECREASE-KEY最多|E|次,这里也用了聚集分析。

Dijkstra算法的运行时间依赖于最小优先队列的实现。可通过利用结点编号1~|V|来维持最小优先队列,将v.d的值存放在数组的第v个记录里。每次INSERT和DECREASE-KEY操作的执行时间为O(1),每次EXTRACT-MIN的操作时间为O(V)(因为需要搜索整个数组),最后算法的总运行时间为O(V2+E)=O(V2)。


4 差分约束和最短路径

不会整理


5 最短路径性质的证明

不会整理


END

算法导论-上课笔记11:单源最短路径相关推荐

  1. 算法设计与分析课程复习笔记11——单源最短路径

    算法设计与分析课程复习笔记11--单源最短路径 单源最短路径 最短路径问题 输入:有权有向图G=(V,E) 路径p={ v 0 , v 1 , . . . , v k v_0, v_1, . . . ...

  2. 【算法设计与分析】 单源最短路径(贪心算法) Dijkstra

    [算法设计与分析] 单源最短路径(贪心算法) Dijkstra [问题描述] Dijkstra算法解决的是带权重的有向图上单源最短路径问题.所有边的权重都为非负值.设置顶点集合S并不断地作贪心选择来扩 ...

  3. AOJ GRL_1_B: Shortest Path - Single Source Shortest Path (Negative Edges) (Bellman-Frod算法求负圈和单源最短路径)

    题目链接: http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_1_B Single Source Shortest Path ( ...

  4. 算法导论-上课笔记7:贪心算法

    文章目录 0 前言 1 活动选择问题 1.1 活动选择问题的最优子结构 1.2 贪心选择 1.3 递归贪心算法 1.4 迭代贪心算法 2 贪心算法原理 2.1 贪心选择性质 2.2 最优子结构 2.3 ...

  5. 算法导论-上课笔记10:最小生成树

    文章目录 0 前言 1 最小生成树 2 Kruskal算法 3 Prim算法 0 前言 在电路设计中,常常需要将多个组件的针脚连接在一起.要连接n个针脚,可以使用n-1根连线,每根连线连接两个针脚,则 ...

  6. 单源路径分支界限java_java单源最短路径算法

    . .. .. . 单源最短路径的 Dijkstra 算法: 问题描述: 给定一... 并 应用贪心法求解单源最短路径问题.环境要求对于环境没有特别要求.对于算法实现,可以自由选择 C, C++, J ...

  7. 单源最短路径---Dijkstra算法

    有这样一道题:在一个图(如图所示)中,一共有四个点:1 2 3 4 这四个点之间各有相连,且每条边都有自己的权值.现在小明在点1上, 他想要到3去,请问最短路径是多少. 很容易得到该图的邻接矩阵.我们 ...

  8. 单源最短路径Dijkstra算法的思想、详细步骤、代码

    目录 一.算法思想 二.算法详细步骤 三.伪代码 + C++代码 四.算法复杂度分析 五.算法改进 六.应用案例 一.算法思想 1.Dijkstra 算法是用来求解单源最短路径问题的经典算法,其本质上 ...

  9. 算法导论之单源最短路径

    单源最短路径,在现实中是很多应用的,是图的经典应用,比如在地图中找出两个点之间的最短距离.最小运费等.单源最短路径的问题:已知图G=(V,E),找出给定源顶点s∈V到每个顶点v∈V的最短路径.单源最短 ...

最新文章

  1. matlab 分段式规范作图
  2. IPv6扩展头部 (三) 路由头部 Routing Header for IPv6
  3. 1362. 健康的荷斯坦奶牛【难度: 一般 / 二进制枚举】
  4. 代码也浪漫:用Python放一场烟花秀!
  5. druid.properties文件的配置
  6. 史上最全阿里Java面试题目大汇总!强烈建议收藏~
  7. 分布式事务模型--TCC
  8. 成为高级网络管理员必学知识
  9. 【clickhouse】ClickHouse中的低基数(LowCardinality)类型
  10. Hashtable 和 HashMap 的区别
  11. 深入理解 Java 之 GC 到底如何工作
  12. 【IPTV】华为IPTV解决方案总体介绍
  13. [深度学习][转载]人脸识别相似度计算方法
  14. 学堂在线计算机通信网络,第二章 数据通信的基础知识 计算机网络笔记 学堂在线 2.4差错控制...
  15. ubuntu和kubuntu换源
  16. manjaro 配置 独立显卡驱动
  17. 【树】B056_LQ_三角形面积 阅兵方阵 版本分支(递归预处理)
  18. keras中的K.gradients()函数
  19. 图像颜色空间转换--RGB to Lαβ
  20. 微信小程序封装echarts组件

热门文章

  1. 建筑物风环境的计算机数值模拟,针对FLUENT软件的建筑物风场数值模拟.pdf
  2. 和一个北京黑出租车司机的对话
  3. Clion配置导致中文乱码问题 char长度限制导致中文乱码问题
  4. 帮助全人类知识无版权传播的计划 - Library Genesis
  5. 计算机辅助旅游景观规划设计pdf,计算机辅助园林景观设计.pdf
  6. Cocos2dx 基础 核心概念 (1)
  7. 创建cocos2dx项目
  8. cocos2dx-标签:Label的使用
  9. 嵌入式linux系统快速启动优化的方法
  10. springboot-定时任务