任意点间求最短路径——弗洛伊德(Floyd)算法

迪杰斯特拉算法求得是 从某个特定的点出发到任意点之间的最短路径,但我们要处理从任一点到任一点怎么办?因此就直接介绍更具普遍意义而且代码写的很优美的弗洛伊德算法。
弗洛伊德算法求的是任意点间的最短路径,为了方便说明,这里先给出一个例子:
任意点间求最短路径——弗洛伊德(Floyd)算法_第1张图片
左边是一个网,右边的带回再解释。我们先来分析这个网,从v1到v2最短的路径是多少?反正不会是5,只要稍微绕个路,先去v0,再去v2,这个权值加起来只有3,所以最短路径应该是3(不能围成三角形的我想说明一下,权值不等同于这条线的长度,只是我们将这个边赋了一个值而已)。
现在来解释右边的四个矩阵。我们定义一个最短路径权值和的矩阵D,还定义一个对应顶点的最小路径的前驱矩阵P。最初的状态,我们记做D-1,其矩阵相当于是这个网的邻接矩阵。首先查看
D-1 [1][0] + D-1 [0][2] = 2 + 1 = 3 < D-1 [1][2] = 5,所以替换成 D-1 [1][2] = 3,由于对称,所以 D-1 [2][1] = 3,修改后记为D0。同时,P-1矩阵的在D-1修改的地方修改自己的前驱,说简单点就是中转站,于是P-1 [1][2] = 0,P-1 [2][1] = 0,记做P0
下面我们来看一个较为复杂的网(下面的网):
任意点间求最短路径——弗洛伊德(Floyd)算法_第2张图片
这是我们要来看的例子。其代码如下:

#define MAXVEX 20
#define INFINITY 65535

typedef struct
{
	int vexs[MAXVEX];
	int arc[MAXVEX][MAXVEX];
	int numVertexes, numEdges;
}MGraph;

typedef int Patharc[MAXVEX][MAXVEX];
typedef int ShortPathTable[MAXVEX][MAXVEX];

/*弗洛伊德(Floyd)算法*/
void ShortestPath_Floyd(MGraph G, Patharc *P, ShortPathTable *D)
{    
	int v,w,k;    
	for(v=0; v(*D)[v][k]+(*D)[k][w])    // 如果经过下标为k顶点路径比原两点间路径更短
				{                                                         
					(*D)[v][w]=(*D)[v][k]+(*D)[k][w];      // 将当前两点间权值设为更小的一个 
					(*P)[v][w]=(*P)[v][k];          // 路径设置为经过下标为k的顶点 
				}
			}
		}
	}
}

假设我们的结构体里面的arc数组已经放好了,就像D-1一样,我i们主要来看弗洛伊德算法。最初的for循环就是初始化D-1和P-1两个数组(如上图下面的两个数组)。
下面就到了三个for循环的嵌套:

for(k=0; k(*D)[v][k]+(*D)[k][w])    // 如果经过下标为k顶点路径比原两点间路径更短
			{                                                         
				(*D)[v][w]=(*D)[v][k]+(*D)[k][w];      // 将当前两点间权值设为更小的一个 
				(*P)[v][w]=(*P)[v][k];          // 路径设置为经过下标为k的顶点 
			}
		}
	}
}

第一个for循环,k是中转点,也就是说我去哪个点都要向Vk点先走。第二个for循环的变量v是起点,第三个是终点,这两个for循环就形成了任一点间路径的计算。我们来过一遍。第一遍,k是0,大家都要经过v0中转,可惜没有变化,记作D0和P0
任意点间求最短路径——弗洛伊德(Floyd)算法_第3张图片
结束了k = 0,来看k = 1,也就是都经过v1中转,D0 [0][1] + D0 [1][2] = 1 + 3 = 4 < D0 [0][2] = 5,取最小值,于是就将
D0 [0][2]改成了4,相应的,P0中的前驱也要改变,改成1。其他的顶点也都是一样的,修正后的已经用红圈标出:
任意点间求最短路径——弗洛伊德(Floyd)算法_第4张图片
接下来K = 2,即每个点都经过v2,可以看看是不是近一些,近的化就修改,相应的改变P矩阵中的前驱,这样循环到最后,我们就得到如下的修正后的结果:
任意点间求最短路径——弗洛伊德(Floyd)算法_第5张图片
这里我们可以从D8,P8这两个矩阵中看到每一行都是迪杰特斯拉算法,比如v0行,就是v0到任意点的路径的权值(D矩阵)以及路径(P矩阵),这样类推,所以弗洛伊德算法就实现了任意点间最短路径。主要是理解它的思想,它做到了用简洁的三个for循环嵌套实现了该需求,简洁明了。可惜的是由于它是三层for嵌套,其时间复杂度是O(n3)级别的。

你可能感兴趣的:(数据结构,算法,最短路径,弗洛伊德)