首页 > 代码库 > 最短路径之Floyd算法

最短路径之Floyd算法

Dijkstra算法求某一个源点到其余各顶点时间复杂度是O(n^2),但如果采用此算法,找从某一源点到某一特定终点的最短路径,复杂度仍为O(n^2)。

求每一对顶点之间的最短路径:

(1)每次以一个顶点为源点,重复执行Dijkstra算法n次。总的时间复杂度是O(n^3);

(2)弗洛伊德(Floyd)算法:时间复杂度也是O(n^3),但形式上更简单。

以如下的有线网为例:

  邻接矩阵为:

利用floyd算法求得的每一对顶点之间的最短路径及其路径长度的过程如下图所示:


具体算法实现代码如下:

//Floyd算法,求网图G中各顶点v到其余顶点w的最短路径P[v][w]及带权长度D[v][w]
void ShortestPath_FLOYD(Graph *g, PathMatrix p[][MAX_VEX], ShortPathTable d[][MAX_VEX])
{
	int v, w, k;
	for (v = 0; v < g->vexNum; v++)
		for (w = 0; w < g->vexNum; w++)
		{
			d[v][w] = g->arc[v][w];	  //初始化权值d^-1和路径p^-1
			p[v][w] = w;
		}

		for (k = 0; k < g->vexNum; k++)
			for (v = 0; v < g->vexNum; v++)
				for (w = 0; w < g->vexNum; w++)
					if (d[v][k] + d[k][w] < d[v][w]) //从v经k到w的一条更短的路径
					{
						d[v][w] = d[v][k] + d[k][w];
						p[v][w] = p[v][k];		//路径设置为经过下标为k的顶点
					}
}// ShortestPath_FLOYD 
下面详细说明执行流程:

(1)程序开始运行,第05-10行代码用于初始化D和P,使得它们成为上图 红框框住的两个矩阵。
(2)第12-19行是算法的主循环,共三层嵌套,k代表的就是中转顶点的下标。v代表起始顶点,w代表结束顶点。
(3)当k = 0时,所有的顶点对间的最短距离都经过顶点A中转

因为只有三个顶点A、B和C:

查看B->A->C,得D-1[1][0] + D-1 [0][2] = 6 + 11 = 17 > D-1 [1][2] = 2,=> D0[1][2] = D-1 [1][2],即D0[1][2]的值不变化。

查看C->A->B,得D-1 [2][0]+ D-1 [0][1] = 3 + 4 = 7 < D-1 [2][1] = ∞,=> D0[1][2] = D-1 [2][0] + D-1 [0][1]=7。因此就得到了数组D0,同时将数组p-1[2][1]的值修改为当前中转顶点的下标0,即p0[2][1] = 0,如此就得到了数组p0

也就是说:

D0[i][j] = Min{D-1[i][j], D-1[i][k]+ D-1[k][j]}

如下图:


一般地,Dk[i][j] = Min{Dk-1[i][j], Dk-1[i][k]+ Dk-1[k][j]}, 0<=k<=n-1,其中D-1[i][j] = G.arcs[i][j]。

(4)k = 1,所有的顶点对间的最短距离都经过顶点B中转:

查看A->B->C,得D0[0][1]+ D0 [1][2] = 4 + 2 = 6< D0 [0][2] = 11=> D1[0][2]= D0[0][1] + D0 [1][2]= 6同时将数组p1[0][2]的值修改为当前中转顶点的下标1,即p1[0][2] = 1

查看C->B->A,得D0 [2][1]+ D0 [1][0] = + 6 => D0 [2][0] = 3=> D1[2][0]= D0 [2][0] = 3,不改变。


(5)k = 2,所有的顶点对间的最短距离都经过顶点C中转:

查看A->C->BD2 [0][1]不改变。

查看B->C->A,得D1 [1][2]+ D1 [2][0] = 2+ 3 = 5 < D1 [1][0] = 6=> D2 [1][0] = D1 [1][2]+ D1 [2][0]同时将数组p2 [1][0]的值修改为当前中转顶点的下标2,即p2 [1][0] = 2

ps:D0是以D-1为基础,D1是以D0为基础,D2是以D1为基础的。最终,当k = 2时,两个矩阵数据为:


验证可以发现D2数组的第1行和Dijkstra计算出来的D数组结果数一样的。

那么如何由P这个路径数组得出具体的最短路径呢?跟Dijkstra算法得到矩阵p后获取某一路径序列是一致的:

以A到C为例,从上图下半部分的P矩阵的第2列,P[0][2]= 1,得到要经过顶点B,然后将1取代0,得到P[1][2] = 2(此时等于终点C的下标了,说明中间的顶点序列只有下标为1的顶点B),推倒出最终的最短路径值为A->B->C。

代码如下:

// 查找从源点v到终点w的路径,并输出
void SearchPath(VertexType vex[], PathMatrix p[][MAX_VEX], int v, int w)
{
	int que[MAX_VEX];
	int tot = 0;
	que[tot++] = w;	 //终点u
	int tmp = p[v][w];   //到顶点下标w的路径上的上一个顶点下标
	while(tmp != w)
	{
		que[tot++] = tmp;
		tmp = p[tmp][w];   //到顶点下标tmp的路径上的上一个顶点下标
	}
	que[tot] = v;
	for(int i = tot; i >= 0; --i)
		if(i != 0)
			printf("%c -> ", vex[que[i]]);
		else
			printf("%c", vex[que[i]]);
}
以上述有向网图为例,程序运行截图为:



参考:blog.chinaunix.net/uid-26548237-id-3834873.html(打开不了呢,发布时总是提示无效url,删掉链接地址开头的http://后倒是不会再提示,但就打不开链接了,不知道怎么解决~)