最短路算法[1]
最短路问题的求解方法

最短路问题的求解方法最短路问题是图论中的一个经典问题,它在很多实际应用中都有着重要的作用。
在现实生活中,我们经常需要求解最短路径,比如在地图导航、网络通信、交通运输等领域。
因此,研究最短路问题的求解方法具有重要的理论意义和实际应用价值。
在图论中,最短路问题的求解方法有很多种,其中比较经典的有Dijkstra算法、Bellman-Ford算法、Floyd-Warshall算法等。
这些算法各有特点,适用于不同的场景和要求。
下面我们就逐一介绍这些算法的原理和求解方法。
Dijkstra算法是一种用于求解单源最短路径的算法,它采用贪心策略,每次找到当前距离最短的节点进行松弛操作,直到所有节点都被遍历。
Dijkstra算法的时间复杂度为O(V^2),其中V为节点的个数。
这种算法适用于边权值为正的图,可以求解从单个源点到其他所有点的最短路径。
Bellman-Ford算法是一种用于求解单源最短路径的算法,它可以处理边权值为负的图,并且可以检测负权回路。
Bellman-Ford算法的时间复杂度为O(VE),其中V为节点的个数,E为边的个数。
这种算法适用于一般情况下的最短路径求解,但是由于其时间复杂度较高,不适用于大规模图的求解。
Floyd-Warshall算法是一种用于求解所有点对最短路径的算法,它可以处理边权值为正或负的图,但是不能检测负权回路。
Floyd-Warshall算法的时间复杂度为O(V^3),其中V为节点的个数。
这种算法适用于求解图中所有点对之间的最短路径,可以同时求解多个源点到多个目标点的最短路径。
除了上述几种经典的最短路求解算法外,还有一些其他的方法,比如A算法、SPFA算法等。
这些算法在不同的场景和要求下有着各自的优势和局限性,需要根据具体情况进行选择和应用。
在实际应用中,最短路问题的求解方法需要根据具体的场景和要求进行选择,需要综合考虑图的规模、边权值的情况、时间效率等因素。
同时,对于大规模图的求解,还需要考虑算法的优化和并行化问题,以提高求解效率。
最短路算法(图论)

2009年春季 图算法及其在通信网络中的应用
DijkstraAlg源码(二)
void CGraph::Update(int v) { list<CEdge*> lEdge = mapVID_listEdge[v]; list<CEdge*>::iterator i,iend; iend = lEdge.end(); for( i = lEdge.begin(); i!=iend; i++) { int w = (*i)->getWeight(); CVertex* h = mapVID_Vertex[(*i)->getHead()]; void CGraph::Dijkstra(int s) CVertex* t = mapVID_Vertex[v]; { if ( t->d + w < h->d ) map<int, CVertex*>::iterator i,iend; { h->d = t->d + w; iend = mapVID_Vertex.end(); h->p = v; for( i=mapVID_Vertex.begin(); i != iend; i++) } { if ( i->second->ID == s) } i->second->d = 0; } listTempMark.pushback(i->second); } Update(s); while( ! listTempMark.empty() ) { listTempMark.sort(pVertexComp); int j = (*listTempMark.begin())->ID; listTempMark.popfront(); Update(j); } }
最短路算法

5
3 10
1 2
2
v1
2
8
4 2 4
v3
6
v5
D ( 0) D
最短路问题在图论应用中处于很重要的地位, 下面举两个实际应用的例子。 例1 设备更新问题 某工厂使用一台设备,每年年初工厂要作出决定: 继续使 用旧的还是购买新的?如果继续使用旧的, 要付维修费;若要购买 一套新的,要付购买费。试 确定一个5年计划,使总支出最小. 若已知设备在各年的购买费,及不同机器役龄时的 残值与维修费,如表所示.
给 (v1 , v5 ) 划成彩线。
59 40 28 30
21
v1 (0)
①
12
v2 (12)
②
19 13
v3 (19)14 20
v4 (28) 15
29
④
15 v5 (40)
22
⑤
v6
③
41
k16 , k26 , k36 , k46 , k56 } ⑹ min{ min{ 59,53,49,50,55} 49
min{ k24 , k25 , k34 , k35} min{ 9,8,10,13} 8
① 给 (v2 , v5 ) 划成粗线。
② 给 v5 标号(8)。 ③ 划第4个弧。
v2 (4)
4
5
4
v4(9)
7
9
5
v6
1
v1 (0)
①
②
6
③
4
5
v8
1
v3(6)
7
v5 (8)
④
6
⑤
v7
5)接着往下考察,有四条路可走:(v2 , v4 ), (v3 , v4 ), (v5 , v6 ), (v5 , v7 ). 可选择的最短路为
networkx 最短路算法

一、网络图简介网络图是一种表示对象之间关系的数学结构,它由一组节点和连接这些节点的边组成。
在现实生活中,网络图可以用来表示交通网络、社交网络、电力网络等各种复杂系统。
在计算机科学中,网络图通常被用于建模和解决各种问题,比如最短路径问题、最小生成树问题、网络流问题等。
二、 NetworkX 简介NetworkX 是一个用 Python 语言编写的开源图论和复杂网络分析工具包,它提供了创建、操作和研究复杂网络的功能。
NetworkX 支持创建各种类型的网络图,包括有向图、无向图、加权图等,并提供了丰富的图算法和分析工具。
其中,最短路径算法是 NetworkX 中的一个重要功能,它可以用来寻找网络图中的最短路径。
三、最短路径算法概述最短路径算法用于寻找网络图中两个节点之间的最短路径,其中路径的长度可以通过边的权重来定义。
最短路径算法有多种实现方式,常见的算法包括 Dijkstra 算法、Bellman-Ford 算法、Floyd-Warshall 算法等。
这些算法在不同场景下具有不同的适用性和效率。
四、 NetworkX 中的最短路径算法在 NetworkX 中,最短路径算法主要包括两种实现方式:单源最短路径算法和全源最短路径算法。
单源最短路径算法用于寻找网络图中某个特定节点到其他所有节点的最短路径,常见的算法有 Dijkstra 算法和 Bellman-Ford 算法;全源最短路径算法用于寻找网络图中任意两个节点之间的最短路径,常见的算法有 Floyd-Warshall 算法。
五、单源最短路径算法1. Dijkstra 算法Dijkstra 算法是一种用于计算单源最短路径的贪心算法,它的基本思想是从起始节点开始,逐步扩展到其他节点,并更新节点之间的最短距离。
具体步骤如下:(1)初始化起始节点到其他所有节点的距离为无穷大,起始节点到自身的距离为 0;(2)选择距离起始节点最近的未访问节点,并更新该节点到其相邻节点的距离;(3)重复上述步骤,直至所有节点都被访问过。
最短路算法

最短路径在一个无权的图中,若从一个顶点到另一个顶点存在着一条路径,则称该路径长度为该路径上所经过的边的数目,它等于该路径上的顶点数减1。
由于从一个顶点到另一个顶点可能存在着多条路径,每条路径上所经过的边数可能不同,即路径长度不同,把路径长度最短(即经过的边数最少)的那条路径叫作最短路径或者最短距离。
对于带权的图,考虑路径上各边的权值,则通常把一条路径上所经边的权值之和定义为该路径的路径长度或带权路径长度。
从源点到终点可能不止一条路径,把带权路径长度最短的那条路径称为最短路径,其路径长度(权值之和)称为最短路径长度或最短距离。
最短路径算法Dijkstra算法:该算法是用于求解单源点最短路径的实用算法。
Dijkstra算法的基本思想如下:设置并逐步扩充一个集合S,存放已求出其最短路径的顶点,则尚未确定最短路径的顶点集合是V-S其中,V为网中所有顶点集合。
按最短路径长度递增的顺序逐个用V-S中的顶点加到S中,直到S中包含全部顶点,而V-S为空。
Dijkstra算法的具体步骤;(1)设源点为V1,则S中只包含顶点V1,令W=V-S,则W中包含除V1外图中所有顶点。
V1对应的距离值为0,即D[1]=0。
W中顶点对应的距离值是这样规定的:若图中有弧 <v1,vk>,则Vj顶点的距离为此弧权值,否则为一个无穷大的数;(2)从W中选择一个其距离值最小的顶点 vk,并加入到S中;(3)每往S中加入一个顶点vk后,就要对W中各个顶点的距离值进行一次修改。
若加进vk做中间顶点,使<v1,vk> + <vk+vj>的值小于<v1,vj> 值,则用<v1,vk> + <vk+vj>代替原来vj 的距离值;(4)重复步骤2和3,即在修改过的W中的选距离值最小的顶点加入到S 中,并修改W中的各个顶点的距离值,如此进行下去,知道S中包含图中所有顶点为之,即S=V。
最短路dijkstra算法详解

最短路dijkstra算法详解最短路问题是图论中的一个经典问题,其目标是在给定图中找到从一个起点到其他所有节点的最短路径。
Dijkstra算法是解决最短路问题的一种常用算法,本文将详细介绍Dijkstra算法的原理、实现以及时间复杂度等相关内容。
一、Dijkstra算法的原理Dijkstra算法是一种贪心算法,其基本思想是从起点开始,逐步扩展到其他节点。
具体而言,Dijkstra算法通过维护一个集合S来记录已经找到了最短路径的节点,以及一个数组dist来记录每个节点到起点的距离。
初始时,S集合为空,dist数组中除了起点外所有节点都被初始化为无穷大。
接下来,重复以下步骤直到所有节点都被加入S集合:1. 从dist数组中选择距离起点最近的未加入S集合的节点u;2. 将u加入S集合;3. 更新与u相邻的未加入S集合的节点v的距离:如果从起点出发经过u可以得到更短的路径,则更新v对应位置上dist数组中存储的值。
重复以上步骤直至所有节点都被加入S集合,并且dist数组中存储了每个节点到起点的最短距离。
最后,根据dist数组中存储的信息可以得到起点到任意节点的最短路径。
二、Dijkstra算法的实现在实现Dijkstra算法时,需要使用一个优先队列来维护未加入S集合的节点,并且每次从队列中选择距离起点最近的节点。
由于C++标准库中没有提供优先队列,因此需要手动实现或者使用第三方库。
以下是一个基于STL堆实现的Dijkstra算法代码示例:```c++#include <iostream>#include <vector>#include <queue>using namespace std;const int INF = 0x3f3f3f3f;vector<pair<int, int>> adj[10001];int dist[10001];void dijkstra(int start) {priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;pq.push(make_pair(0, start));dist[start] = 0;while (!pq.empty()) {int u = pq.top().second;pq.pop();for (auto v : adj[u]) {if (dist[u] + v.second < dist[v.first]) {dist[v.first] = dist[u] + v.second;pq.push(make_pair(dist[v.first], v.first));}}}}int main() {int n, m, start;cin >> n >> m >> start;for (int i = 1; i <= n; i++) {dist[i] = INF;}for (int i = 1; i <= m; i++) {int u, v, w;cin >> u >> v >> w;adj[u].push_back(make_pair(v, w));}dijkstra(start);for (int i = 1; i <= n; i++) {if (dist[i] == INF) {cout << "INF" << endl;} else {cout << dist[i] << endl;}}return 0;}```以上代码中,adj数组用于存储图的邻接表,dist数组用于存储每个节点到起点的最短距离。
最短路算法分析

最短路算法分析最短路算法分析如下图所⽰,我们把边带有权值的图称为带权图。
边的权值可以理解为两点之间的距离。
⼀张图中任意两点间会有不同的路径相连。
最短路就是指连接两点的这些路径中最短的⼀条。
对于所有求最短路的算法,都是基于⼀个最基础的思想,那就是:松弛。
什么叫松弛呢?简单的说,就是刷新最短路。
那,怎么刷新呢?我们想,能刷新最短路的有啥?就是⽤最短路(边也可能是最短路)。
要⽤魔法打败魔法以下图为例,点1到点3的距离是2,点3到点2的距离是1,⽽图中1到2的距离是6,那么,很明显点1到点3到点2⽐点1直接到点2短得多,那么,我们的最短路dis[1][2]就等于dis[1][3]+dis[3][2]。
我们可以这么理解:1到3这条边的边权已经是1到3的最短路了,同样,2到3也是,那我们就可以⽤这两条最短路来刷新1到2的最短路,这就是⽤最短路来松弛最短路了。
那么,基于松弛操作,我们就有了⾮常多种求最短路的算法,这些算法各有神通,各有缺陷,都应该熟练掌握且能在考场上准确判断该⽤那种算法。
1、Floyed:学过最短路的⼈,⼤多数都会认为:Floyed就是暴⼒,简单粗暴,简单得很。
其实,如果你仔细品读这个算法,会发现:虽然代码简单,但是其思想却⾮常的巧妙!我们来分析⼀下:我们要求最短路,我们需要通过中转点来进⾏松弛,那我们要怎么找中转点呢?显然,必须得枚举。
那,怎么枚举呢?我们⾃⼰画画图就知道,⼀些最短路可以拐来拐去,也就是中转点有很多,那我们怎么枚举?这就是Floyed的巧妙之处,它⽤到的是动态规划的思想。
对于规模很⼤的问题,我们的⼀般策略应该是:缩⼩规模。
不管它可能有多少个,我们慢慢从少往多推。
假设我们现在不允许有中转点,那么各个点之间的最短路应该是题⽬给出来的边权。
现在我们只允许通过1号节点来进⾏转移,注意是1号⽽不是1个,如果讨论个数的话其实就回到了我们上⾯的问题:“怎么枚举?”。
现在我们只需要枚举i和j,⽐较dis[i][1]+dis[1][j]和dis[i][j]的⼤⼩,如果⼩于则刷新,这就是松弛。
掌握最短路算法的要点

掌握最短路算法的要点最短路算法是图论中的一个重要概念,其应用广泛且具有实际意义。
无论是在计算机科学还是数据分析领域,掌握最短路算法的要点都是非常重要的。
本文将详细介绍最短路算法的概念、应用以及其要点。
一、最短路算法概述最短路算法是用来求解图中两点之间最短路径问题的算法。
该算法考虑了图中各点之间的边权重,通过比较路径的权重来确定最短路径。
最常用的最短路算法有迪杰斯特拉算法和弗洛伊德算法。
迪杰斯特拉算法是一种单源最短路径算法,用于求解一个节点到其他所有节点之间的最短路径。
它通过不断选择未访问节点中权重最小的节点来更新节点之间的距离。
弗洛伊德算法是一种多源最短路径算法,用于求解图中任意两点之间的最短路径。
它通过动态规划的方式逐步更新节点之间的距离。
弗洛伊德算法适用于解决稠密图中的最短路径问题。
二、最短路算法应用最短路算法有着广泛的应用。
下面将介绍几个常见的应用场景。
1. 网络路由在计算机网络中,最短路算法被广泛应用于路由器的路径选择。
路由器根据最短路算法计算出数据包传输的最优路径,以提高网络传输效率和速度。
2. 交通规划最短路算法在交通规划中也有着重要的应用。
比如,在GPS导航系统中,通过最短路算法可以计算出车辆行驶的最短路径,帮助司机选择最快的道路。
3. 电力系统规划在电力系统规划中,最短路算法可以用于计算电力传输的最短路径,以确保电力系统的可靠性和高效性。
通过最短路算法可以优化电力线路的配置和布置。
三、最短路算法要点要想熟练掌握最短路算法,需要注意以下几个要点。
1. 图的表示在实现最短路算法之前,需要先清楚如何表示图。
常见的图表示方法有邻接矩阵和邻接表。
邻接矩阵适用于稠密图,而邻接表适用于稀疏图。
2. 权重的定义在最短路算法中,边的权重是一个重要的因素。
不同的应用场景可能对权重有不同的定义。
比如,在交通规划中,权重可以表示为路径的时间或者距离。
在电力系统规划中,权重可以表示为电力线路的传输损耗。
3. 路径选择策略最短路算法的核心在于选择路径的策略。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
最短路算法及其应用广东北江中学余远铭【摘要】最短路问题是图论中的核心问题之一,它是许多更深层算法的基础。
同时,该问题有着大量的生产实际的背景。
不少问题从表面上看与最短路问题没有什么关系,却也可以归结为最短路问题。
本文较详尽地介绍了相关的基本概念、常用算法及其适用范围,并对其应用做出了举例说明,侧重于模型的建立、思考和证明的过程,最后作出总结。
【关键字】最短路【目录】一、基本概念 (2)1.1 定义 (2)1.2简单变体 (2)1.3负权边 (3)1.4重要性质及松弛技术 (4)二、常用算法 (5)2.1 Dijkstra算法 (5)2.2 Bellman-Ford算法 (7)2.3 SPFA算法 (8)三、应用举例 (10)3.1 例题1——货币兑换 (10)3.2 例题2——双调路径 (11)3.3 例题3——Layout (13)3.4 例题4——网络提速 (15)四、总结 (18)【正文】一、基本概念1.1 定义乘汽车旅行的人总希望找出到目的地尽可能短的行程。
如果有一张地图并在地图上标出了每对十字路口之间的距离,如何找出这一最短行程?一种可能的方法是枚举出所有路径,并计算出每条路径的长度,然后选择最短的一条。
然而我们很容易看到,即使不考虑含回路的路径,依然存在数以百万计的行车路线,而其中绝大多数是没必要考虑的。
下面我们将阐明如何有效地解决这类问题。
在最短路问题中,给出的是一有向加权图G=(V ,E),在其上定义的加权函数W:E →R 为从边到实型权值的映射。
路径P=(v 0, v 1,……, v k )的权是指其组成边的所有权值之和:11()(,)ki i i w p w v v -==∑定义u 到v 间最短路径的权为{}{}min ():)w p u v u v v δυ→(,=∞ 如果存在由到的通路如果不存在从结点u 到结点v 的最短路径定义为权())w p v δυ=(,的任何路径。
在乘车旅行的例子中,我们可以把公路地图模型化为一个图:结点表示路口,边表示连接两个路口的公路,边权表示公路的长度。
我们的目标是从起点出发找一条到达目的地的最短路径。
边的权常被解释为一种度量方法,而不仅仅是距离。
它们常常被用来表示时间、金钱、罚款、损失或任何其他沿路径线性积累的数量形式。
1.2简单变体单目标最短路径问题: 找出从每一结点v 到某指定结点u 的一条最短路径。
把图中的每条边反向,我们就可以把这一问题转化为单源最短路径问题。
单对结点间的最短路径问题:对于某给定结点u 和v ,找出从u 到v 的一条最短路径。
如果我们解决了源结点为u 的单源问题,则这一问题也就获得了解决。
对于该问题的最坏情况,从渐进意义上看,目前还未发现比最好的单源算法更快的方法。
每对结点间的最短路径问题:对于每对结点u 和v ,找出从u 到v 的最短路径。
我们可以用单源算法对每个结点作为源点运行一次就可以解决问题。
1.3负权边在某些单源最短路问题中,可能存在权为负的边。
如果图G(V ,E)不包含由源s 可达的负权回路,则对所有s v V ∈,最短路径的权的定义(,)s v δ依然正确。
即使它是一个负值也是如此。
但如果存在一从s 可达的负权回路,最短路径的定义就不能成立了。
从s 到该回路上的结点不存在最短路径——因为我们总可以顺着找出的“最短”路径再穿过负权回路从而获得一权值更小的路径,因此如果从s 到v 的某路径中存在一负权回路,我们定义(,)s v δ=-∞。
图1 含有负权和负权回路的图图1说明负的权值对最短路径的权的影响。
每个结点内的数字是从源点s 到该结点的最短路径的权。
因为从s 到a 只存在一条路径(路径<s,a>),所以:(,)(,)3s a w s a δ==。
类似地,从s 到b 也只有一条通路,所以:(,)(,)(,)3(4)1s b w s a w a b δ=+=+-=-。
从s 到c 则存在无数条路径:<s,c>,<s,c,d,c>,<s,c,d,c,c,d,c>等等。
因为回路<c,d,c>的权为6+(-3)=3>0,所以从s 到c 的最短路径为<s,c>,其权为:(,)5s c δ=。
类似地,从s 到d 的最短路径为<s,c,d>,其权为:(,)(,)(,)11s d w s c w c d δ=+=。
同样,从s 到e 存在无数条路径:<s,e>,<s,e,f,e>,<s,e,f,e,f,e>等等.由于回路<e,f,e>的权为3+(-6)=-3<0,所以从s 到e 没有最短路径。
只要穿越负权回路任意次,我们就可以发现从s 到e 的路径可以有任意小的负权值,所以:(,)s e δ=-∞类似地,(,)s f δ=-∞因为g 是从f 可达的结点,我们从s 到g 的路径可以有任意小的负权值,则:(,)s g δ=-∞。
结点h ,j ,i 也形成一权值为负的回路,但因为它们从s 不可达,因此(,)(,)(,)s h s i s j δδδ===∞。
一些最短路径的算法,例如Dijkstra 算法,都假定输入图中所有边的权取非负数,如公路地图实例。
另外一些最短路算法,如Bellman-Ford 算法,允许输入图中存在权为负的边,只要不存在从源点可达的权为负的回路,这些算法都能给出正确的解答。
特定地说,如果存在这样一个权为负的回路,这些算法可以检测出这种回路的存在。
1.4重要性质及松弛技术本文的算法所运用的主要技术是松弛技术,它反复减小每个结点的实际最短路径的权的上限,直到该上限等于最短路径的权。
让我们看看如何运用松弛技术并正式证明它的一些特性。
定理1 (最优子结构) 给定有向加权图G=(V ,E),设P=<v 1, v 2,…, v k >为从结点v 1到结点v k 的一条最短路径,对任意i,j 有i<=j<=k ,设P ij =< v i , v i+1,…, v j >为从v i 到v j 的P 的子路径,则P ij 是从v i 到v j 的一条最短路径。
证明:我们把路径P 分解为<v 1,v 2,…,v i ,v i+1,…v j ,…v k >。
则w(P)=w(P 1i )+w(P ij )+w(P jk )。
现在假设从v i 到v j 存在一路径P ’ij ,且w(P ’ij )<w(P ij ),则将P 中的路径P ij =(v i ,v i+1,…v j )替换成P ’ij ,依然是从v 1到v k 的一条路径,且其权值 w(P 1i )+w(P ’ij )+w(P jk )小于w(P),这与前提P 是从v 1到v k 的最短路径矛盾。
(证毕)下面看定理1的一个推论,它给出了最短路径的一个简单而实用的性质: 推论1.1 给定有向加权图G=(V ,E),源点为s ,则对于所有边(u,v)⊂E ,有(,)(,)(,)s v s u w u v δδ≤+证明: 从源点s 到结点v 的最短路径P 的权不大于从s 到v 的其它路径的权。
特别地,路径P 的权也不大于某特定路径的权,该特定路径为从s 到u 的最短路径加上边(u,v)。
(证毕)下面介绍松弛技术。
对每个结点v ∈V ,我们设置一属性d[v]来描述从源s 到v 的最短路径的权的上界,称之为最短路径估计。
我们通过下面的过程对最短路径估计和先辈初始化。
经过初始化以后,对所有v ∈V ,π[v]=NIL ,对v=s ,d[v]=0,对v ∈V-{s},INITIALIZE-SINGLE-SOURCE(G ,s) 1. For 每个结点 v ∈V[G] 2. Do d[v]←∞ 3. π[v]←NIL 4. d[s]←0d[v]= ∞。
松弛一条边(u,v)的过程包括测试我们是否可能通过结点u对目前找出的到v的最短路径进行改进,如果可能则更新d[v]和π[v],一次松弛操作可以减小最短路径的估计值d[v]并更新v的先辈域π[v],下面的代码实现了对边(u,v)的进一步松弛操作。
RELAX(u,v,w)1.If d[v]>d[u]+w(u,v)2.Then d[v]←d[u]+w(u,v)3.π[v]←u图2 对边(u,v)进行松弛图2说明了松弛一条边的两个实例,在其中一个例子中最短路径估计减小,而在另一实例中最短路径估计不变。
(a)因为在进行松弛以前d[v]>d[u]+w[u,v],所以d[v]的值减小。
(b)因为松弛前d[v]<=d[u]+w[u,v],所以松弛不改变d[v]得值。
下文介绍的每个算法都调用INITIALIZE-SINGLE-SOURCE,然后重复对边进行松弛的过程RELAX。
区别在于对每条边进行松弛操作的次数以及对边执行操作的次序有所不同。
需要指出的是,松弛是改变最短路径估计和先辈的唯一方式。
二、常用算法这一节着重讨论两种常用算法:Dijkstra算法和Bellman-Ford算法。
虽然它们都是建立在松弛技术基础上的算法,但是在实现上有着各自的特点,适用的范围也有所不同。
另外,我们还将介绍一种期望复杂度与边数同阶的高效算法——SPFA算法,并对其复杂度作出简要的分析。
2.1 Dijkstra算法Dijkstra算法解决了有向加权图的最短路径问题,该算法的条件是该图所有边的权值非负,因此在本小节我们约定:对于每条边(u,v)∈E,w(u,v)>=0。
Dijkstra算法中设置了一结点集合S,从源结点s到集合S中结点的最终最短路径的权均已确定,即对所有结点v∈S,有d[v]=δ(s,v)。
算法反复挑选出其最短路径估计为最小的结点u∈V-S,把u插入集合S中,并对离开u 的所有边进行松弛。
在下列算法实现中设置了优先队列Q,该队列包含所有属于V-S的结点,且队列中各结点都有相应的d值。
算法假定图G由临接表表示。
Dijkstra(G,w,s)1.INITIALIZE-SINGLE-SOURCE(G,S)2.S←∅3.Q←V[G]4.While Q≠∅5.Do u←EXTRACT-MIN(Q)6.S←S U{u}7.For 每个顶点v∈Adj[u]8.Do RELAX(u,v,w)Dijkstra算法如图3所示对边进行松弛操作,最左结点为源结点,每个结点内为其最短路径估计。
图3 Dijkstra算法的执行流程阴影覆盖的边说明了前驱的值:如果边(u,v)为阴影所覆盖,则π[v]=u。
黑色结点属于集合S,白色结点属于优先队列Q=V-S。
第1行对d和π值进行通常的初始化工作。
第2行置集合S为空集。