Floyd算法和Dijkstra算法都可以用于计算加权有向图中两顶点之间的最短路径,但是Floyd算法要相对简单许多,而且当该算法完成时,我们可以得到图中任两点之间的最短路径。
算法实现
我们通过先限制任两点之间可经过的顶点来计算此时的最短路径,然后逐渐放宽这一限制,最终允许这两点之间的路径经过任何顶点,从而确定这两点在整张图上的最短路径。
用二维数组minDistance来记录两点之间的有向最短路径长度,用k来描述经过顶点的限制,小于等于k的顶点是允许经过的顶点。起初k=0,表示两点间的最短路径不允许经过任何其他顶点,此时minDistance就是邻接矩阵。然后k逐渐增加,k每增加1,我们需要检验所有两点间的最短路径是否因新加入的顶点而发生改变,例如当k增加到k0时,新加入的顶点是k0,我们需要对任意顶点i,j,检验他们之间的最短路径是否要被替换为i到k0的最短路径加上k0到j的最短路径。当k=n是,限制消失,最终得到在整张图上的任两点的最短距离。
代码
这个函数属于加权有向图类adjacencyWDigraph,此处不做详细说明。
关于类adjacencyWDigraph的完整设计,请见有向图(邻接数组描述)
void Floyd(T** minDistance, int** passBy)//Floyd算法:计算任两顶点之间的最短距离。将最短距离存入二维数组minDistance中,将最后一次经过的顶点存入二维数组passBy中(用于记录具体最短路径)
{
for (int i = 0; i <= n; i++)//当k=0时,任两点的路径都不允许经过任何其他顶点,minDistance此时就是有向图的邻接矩阵
{
for (int j = 0; j <= n; j++)
{
minDistance[i][j] = a[i][j];
passBy[i][j] = 0;
}
}
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
//当k增加了一个的时候,检查两顶点的最短路径是否因为加入的新顶点而发生改变,即最短路径是否因经过新顶点而变短
if (i!=j && minDistance[i][k] != noEdge && minDistance[k][j] != noEdge && (minDistance[i][j] == noEdge || minDistance[i][j] > minDistance[i][k] + minDistance[k][j]))
{
minDistance[i][j] = minDistance[i][k] + minDistance[k][j];
passBy[i][j] = k;//每经过一个新顶点,就用新顶点覆盖一次
}
}
}
}
//循环结束之后,minDistance所存数据即为两顶点之间有向最短路径的长度
}
借助另外一个二维数组,实现对路径上经过顶点的输出。
void Floyd_getPath(int** passBy, int start, int end)//利用passBy[][],递归输出两顶点最短路径上经过的顶点(不输出起点)
{
if (start == end)
return;
if (passBy[start][end] == 0)//等于0说明这两点之间的最短路径没有经过其他任何顶点
cout << end << " ";
else//若经过了其他顶点,则分两半递归
{
Floyd_getPath(passBy, start, passBy[start][end]);
Floyd_getPath(passBy, passBy[start][end], end);
}
}