本文主要介绍求单源最短路径的三个主要算法diijkstar、spfa、floy。文末给出完整代码。在正式分析算法时,我们需要先了解一些基本知识:
最短路径依赖于一个重要性质:两个结点之间的一条最短路包含着其他的最短路径。
松弛操作:从s到v的最短路径,与从s到u的最短路径+u到v的边权重,两者进行比较,取最小值,并更新最短路径的估计值及v的前驱属性。通俗的讲就是两边之和大于第三边。
三角不等式:对于任何边(u,v)∈E,都有δ(s,v)≤δ(s,u)+w(u,v)
非路径性质:如果从结点s到结点v之间不存在路径,则总是有v.d = δ(s,v) = ∞
收敛性质:对于某些结点u,v∈V,如果s到u→v是图G的一条最短路径,并且在对(u,v)进行松弛操作前的任意时间有u.d = δ(s,u),则在之后的所有时间都有v.d = δ(s,v)
路径松弛性质:如果p=<v0,v1,···,vk>是从源节点s=v0到结点vk的一条最短路径,且我们对p中边所进行松弛操作的次序为(v0,v1),(v1,v2),···,(vk-1,vk)则vk.d=δ(s,vk)。
前驱子图性质:对于所有结点v∈V,一旦v.d=δ(s,v),则前驱子图是一棵根节点为s的最短路径树。
基于这些性质我们开始分析算法,首先是floyd算法
floy算法
floy算法中的图采用邻接矩阵进行存储,然后枚举n各顶点,对邻接矩阵进行二重循环遍历,采用松弛操作进行距离的缩短。最终得到的距离矩阵中,每一个元素的值即为从(行数)到(列数)的距离
核心代码如下
int _Map[110][110];
int n3, m3;
void floyd()
{
cout << "请输入点数和边数:" << endl;
cin >> n3 >> m3;
memset(_Map, 0, sizeof(_Map));
for (int i = 1; i <= n3; ++i)
for (int j = 1; j <= n3; ++j)
cin >> _Map[i][j];
cout << "floyed算法结果:" << endl;
for (int k = 1; k <= n3; ++k)
for (int i = 1; i <= n3; ++i)
for (int j = 1; j <= n3; ++j)
if (_Map[i][j] > _Map[i][k] + _Map[k][j])
_Map[i][j] = _Map[i][k] + _Map[k][j];
for (int i = 1; i