floyd算法是非单源最短路算法的一种;非单源即算法运行一次,可求出任意节点至任意可到达节点的最短路长度,其时间复杂度为O(n^3)。
相较于单源算法dijkstra求最短路,floyd有更简洁的代码。关于dijkstra求最短路长度,请点击这里;如果你还想记录dijkstra最短路的路径,请点击这里。
下面有两个问题:
1. 将任意一条通路取出拉直后就如图一所示,我们想知道用floyd最终能否产生AD的直接通路?(直接通路即节点间有弧直接连接,非科学定义)
最初,图中只有AB,BC,CD三条通路。如果先将C作为中途节点,那么由BC和CD将产生BD这条直接通路。接着再以节点B作为中途节点,由AB和BC产生直接通路AC,由AB和BD(BD刚刚产生)会产生直接通路AD。即使打乱中途节点的顺序,最终仍会获得AD这条直接通路。
所以无论谁先作为中途节点,只要将所有节点均作为过中途节点之后,原本连通的节点之间一定会产生直接通路。
2. 我们想知道用floyd求出图二的AD直接通路长度一定是从A到D的最短长度吗?
最初,图中有AE=5,AB=10,EC=5,BC=10,CD=10这五条直接的通路。如果先将B作为中途节点,则通过AB和BC产生AC=20这条直接通路。再以节点C作为中途节点,则通过EC和CD产生直接通路ED=15,通过BC和CD产生直接通路BD=20,通过AC(AC刚刚产生)和CD产生直接通路AD=30。再以节点E作为中途节点,可由AE和EC得到直接通路AC=10(小于原有的AC=20,更新),再由AE和ED得到直接通路AD=20(小于原有的AD=30,更新)。
所以无论谁先作为中途节点,只要将所有节点均作为过中途节点之后,则所有直接通路的长度定是这两个节点间的最短路长度。
下面是求图3所有节点之间最短路长度的代码(floyd):
#include<stdio.h>
const int INF=10000; //INF表示无穷大,这里假设为10000
const int N=100;
int p[N][N]; //p表示各节点间的距离,不存在路径即为无穷大
void floyd(int n) //n表示节点总数
{
int i,j,k;
for(k=0;k<n;k++) //k表示中途节点,每次将一节点作为中途节点后,都需要更新所有节点之间的最短长度
{
for(i=0;i<n;i++) //i表示出发节点
{
for(j=0;j<n;j++)//j表示结束节点
{
if(p[i][j]>p[i][k]+p[k][j])
{
p[i][j]=p[i][k]+p[k][j];//如果节点i到节点j经过节点k有更短的长度,则更新
}
}
}
}
}
int main()
{
int i,j,n=5; //n表示节点总数
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
p[i][j]=i==j?0:INF;//初始化:i到j路径为无穷大或者i到i本身为0
}
}
p[0][1]=10;p[0][3]=30;p[0][4]=100;p[1][2]=50;p[2][4]=50;p[3][2]=20;p[3][4]=60;//p[i][j]表示节点i到节点j的距离
floyd(n);
for(i=0;i<n;i++) //打印所有节点之间的最短路长度
{
for(j=0;j<n;j++)
{
printf(j==n-1?"%d=>%d:%-5d\n":"%d=>%d:%-5d ",i,j,p[i][j]);
}
printf("\n");
}
return 0;
}
运行结果: