为了能讲明白弗洛伊德(Floyd)算法的精妙所在,我们先来看最简单的案例。下图是一个最简单的3个顶点连通网图。
我们先定义两个二维数组D[3][3]和P[3][3],D代表顶点到顶点的最短路径权值和的矩阵。P代表对应顶点的最小路径的前驱矩阵。在未分析任何顶点之前,我们将D命名为,其实它就是初始的图的邻接矩阵。将P命名为
,初始化为图中所示的矩阵。
首先我们来分析,所有的顶点经过v0后到达另一顶点的最短路径。因为只有三个顶点,因此需要查看v1→v0→v2,得到 [1][0] +
[0][2] = 2+1 = 3。
[1][2] 表示的是v1→v2的权值为5,我们发现
[1][2] >
[1][0] + D1[0][2],通俗的话讲就是v1→v0→v2比直接v1→v2距离还要近。所以我们就让
[1][2] =
[1][0] +
[0][2] = 3,同样的
[2][1] = 3,于是就有了
的矩阵。因为有变化,所以P矩阵对应的
[1][2] 和
[2][1] 也修改为当前中转的顶点v0的下标0,于是就有了
。也就是说
,此时的
和
分别是
接下来,其实也就是在和
的基础上继续处理所有顶点经过v1和v2后到达另一顶点的最短路径,得到
和
、
和
完成所有顶点到所有顶点的最短路径计算工作。
现在我们来看一下弗洛伊德(Floyd)算法的具体实现,我们先给出下图所示的网以及它的和
矩阵:
D代表顶点到顶点的最短路径权值和的矩阵。P代表对应顶点的最小路径的前驱矩阵。
扫描二维码关注公众号,回复: 14436935 查看本文章![]()
具体实现:
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
#define MAXVEX 100//最大顶点数
typedef char VertexType;//顶点类型
typedef int EdgeType;//边上的权值类型
typedef struct
{
VertexType vexs[MAXVEX];//顶点表
EdgeType arc[MAXVEX][MAXVEX];//邻接矩阵
int numVertexte;//当前顶点数
int numEdges;//当前边数
}MGraph;
void ShortestPath_Floyd(MGraph G, vector<vector<int>>& P, vector<vector<int>>& D)
{
for (int i = 0; i < G.numVertexte; ++i)
{
for (int j = 0; j < G.numVertexte; ++j)
{
D[i][j] = G.arc[i][j];//用G的邻接矩阵初始化D
P[i][j] = j;
}
for (int i = 0; i < G.numVertexte; ++i)
{
for (int j = 0; j < G.numVertexte; ++j)
{
for (int w = 0; w < G.numVertexte; ++w)
{
if (D[j][w] > D[j][i] + D[i][w])//如果经过下标为i的顶点路径比原两点间路径更短
{
D[j][w] = D[j][i] + D[i][w];//更新D的值
P[j][w] = P[j][i];//更新P的值
}
}
}
}
}
}
/*我们可以通过下面这个函数将最短路径打印出来*/
void Print(MGraph G, vector<vector<int>>& P, vector<vector<int>>& D)
{
for (int i = 0; i < G.numVertexte; ++i)
{
for (int j = i+1; j < G.numVertexte; ++j)
{
printf("v%d-v%d weight:%d ", i, j, D[i][j]);//打印源点 终点 以及他们之前的权
int k = P[i][j];//第一个路径顶点下标
printf(" path:%d", i);//打印源点
while (k != j)//如果没有到终点
{
printf("-> %d", k);//打印路径顶点
k = P[k][j];//获取下一个路径顶点下标
}
printf(" -> %d\n", j);//打印终点
}
printf("\n");
}
}
最终我们得到的结果如下图所示:
那么如何由P这个路径数组得出具体的最短路径呢?以v0到v8为例,从上图的右图第v8列,P[0][8]=1,得到要经过顶点v1,然后将1取代0得到P[1][8]=2,说明要经过v2,然后将2取代1得到P[2][8]=4,说明要经过V4,然后将4取代2得到P[4][8]=3,说明要经过V3,…,这样很容易就推导出最终的最短路径值为v0→v1->v2→v4->v3->v6->v7->v8。
如果你面临需要求所有顶点至所有顶点的最短路径问题时,弗洛伊德(Floyd)算法应该是不错的选择。时间复杂度为。
另外,我们虽然对求最短路径的两个算法举例都是无向图,但它们对有向图依然有效,因为二者的差异仅仅是邻接矩阵是否对称而已。