通过前一节对迪杰斯特拉算法的学习,主要解决从网(带权图)中某一顶点计算到其它顶点之间的最短路径问题。如果求有向网中每一对顶点之间的最短路径,使用迪杰斯特拉算法的解决思路是:以每一个顶点为源点,执行迪杰斯特拉算法。这样可以求得每一对顶点之间的最短路径。本节介绍另外一种解决算法,也就是弗洛伊德算法,该算法相比于使用迪杰斯特拉算法在解决此问题上的时间复杂度虽然相同,都为
0
1
2
3
4
5
0,5,100
0,4,30
0,2,10
1,2,5
2,3,50
3,5,10
4,3,20
4,5,60
-1 -1 -1 4 -1 4
-1 -1 -1 2 -1 3
-1 -1 -1 -1 -1 3
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 3
-1 -1 -1 -1 -1 -1
65535 65535 10 50 30 60
65535 65535 5 55 65535 65
65535 65535 65535 50 65535 60
65535 65535 65535 65535 65535 10
65535 65535 65535 20 65535 30
65535 65535 65535 65535 65535 65535
O(n3)
,但是弗洛伊德算法的实现形式更简单。弗洛伊德的核心思想是:对于网中的任意两个顶点(例如顶点 A 到顶点 B)来说,之间的最短路径不外乎有 2 种情况:
- 直接从顶点 A 到顶点 B 的弧的权值为顶点 A 到顶点 B 的最短路径;
- 从顶点 A 开始,经过若干个顶点,最终达到顶点 B,期间经过的弧的权值和为顶点 A 到顶点 B 的最短路径。
对于 V0 来说,由于该顶点只有出度,没有入度,所以没有作为中间点的可能。同理,V1也没有可能。将 V2 作为每对顶点的中间点,有影响的为 (V0,V3) 和 (V1,V3):
例如,(V0,V3)权值为无穷大,而(V0,V2)+(V2,V3)= 60,比之前的值小,相比而言后者的路径更短;同理 (V1,V3)也是如此。更新的表格为: 以 V3 作为中间顶点遍历各队顶点,更新后的表格为: 以 V4 作为中间顶点遍历各队顶点,更新后的表格为: 而对于顶点 V5 来说,和顶点 V0 和 V1 相类似,所不同的是,V5 只有入度,没有出度,所以对各队顶点的距离不会产生影响。最终采用弗洛伊德算法求得的各个顶点之间的最短路径如上图所示。
弗洛伊德算法的具体实现
#include #define MAX_VERtEX_NUM 20 //顶点的最大个数#define VRType int //表示弧的权值的类型#define VertexType int //图中顶点的数据类型#define INFINITY 65535typedef struct { VertexType vexs[MAX_VERtEX_NUM]; //存储图中顶点数据 VRType arcs[MAX_VERtEX_NUM][MAX_VERtEX_NUM]; //二维数组,记录顶点之间的关系 int vexnum,arcnum; //记录图的顶点数和弧(边)数}MGraph;typedef int PathMatrix[MAX_VERtEX_NUM][MAX_VERtEX_NUM]; //用于存储最短路径中经过的顶点的下标typedef int ShortPathTable[MAX_VERtEX_NUM][MAX_VERtEX_NUM]; //用于存储各个最短路径的权值和//根据顶点本身数据,判断出顶点在二维数组中的位置int LocateVex(MGraph * G,VertexType v){ int i=0; //遍历一维数组,找到变量v for (; ivexnum; i++) { if (G->vexs[i]==v) { break; } } //如果找不到,输出提示语句,返回-1 if (i>G->vexnum) { printf("no such vertex.\n"); return -1; } return i;}//构造有向网void CreateUDG(MGraph *G){ scanf("%d,%d",&(G->vexnum),&(G->arcnum)); for (int i=0; ivexnum; i++) { scanf("%d",&(G->vexs[i])); } for (int i=0; ivexnum; i++) { for (int j=0; jvexnum; j++) { G->arcs[i][j]=INFINITY; } } for (int i=0; iarcnum; i++) { int v1,v2,w; scanf("%d,%d,%d",&v1,&v2,&w); int n=LocateVex(G, v1); int m=LocateVex(G, v2); if (m==-1 ||n==-1) { printf("no this vertex\n"); return; } G->arcs[n][m]=w; }}//弗洛伊德算法,其中P二维数组存放各对顶点的最短路径经过的顶点,D二维数组存储各个顶点之间的权值void ShortestPath_Floyed(MGraph G,PathMatrix *P,ShortPathTable *D){ //对P数组和D数组进行初始化 for (int v=0; v for (int w=0; w (*D)[v][w]=G.arcs[v][w]; (*P)[v][w]=-1; } } //拿出每个顶点作为遍历条件 for (int k=0; k //对于第k个顶点来说,遍历网中任意两个顶点,判断间接的距离是否更短 for (int v=0; v for (int w=0; w //判断经过顶点k的距离是否更短,如果判断成立,则存储距离更短的路径 if ((*D)[v][w] > (*D)[v][k] + (*D)[k][w]) { (*D)[v][w]=(*D)[v][k] + (*D)[k][w]; (*P)[v][w]=k; } } } }}int main(){ MGraph G; CreateUDG(&G); PathMatrix P; ShortPathTable D; ShortestPath_Floyed(G, &P, &D); for (int i=0; i for (int j=0; j printf("%d ",P[i][j]); } printf("\n"); } for (int i=0; i for (int j=0; j printf("%d ",D[i][j]); } printf("\n"); } return 0;}
运行结果为(以图 1 为例)
6,80
1
2
3
4
5
0,5,100
0,4,30
0,2,10
1,2,5
2,3,50
3,5,10
4,3,20
4,5,60
-1 -1 -1 4 -1 4
-1 -1 -1 2 -1 3
-1 -1 -1 -1 -1 3
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 3
-1 -1 -1 -1 -1 -1
65535 65535 10 50 30 60
65535 65535 5 55 65535 65
65535 65535 65535 50 65535 60
65535 65535 65535 65535 65535 10
65535 65535 65535 20 65535 30
65535 65535 65535 65535 65535 65535
其中,输出结果中 65535 表示该位置所表示的两顶点之间的距离为无穷大。