一:
该算法解决的问题是对于一个图,对该图的没一对顶点vi != vj,要求求出vi与vj之间的最短路径和最短路径长度。
二:算法思想
正如我们所知道的,Floyd算法用于求最短路径。Floyd算法可以说是Warshall算法的扩展,三个for循环就可以解决问题,所以它的时间复杂度为O(n^3)。
Floyd算法的基本思想如下:从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从a到b,2是从a经过若干个节点x到b。所以,我们假设A[a][b]为节点a到节点b的最短路径的距离,对于每一个节点x,我们检查A[a][x] + A[x][b] < A[a][b]是否成立,如果成立,证明从a到x再到b的路径比a直接到b的路径短,我们便设置A[a][b]=A[a][x]+A[x][b],这样一来,当我们遍历完所有节点x,A[a][b]中记录的便是a到b的最短路径的距离。
接下来都是一段代码更简明阐述:
for(k=0;k<n;k++)
{
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(k==i||k==j)
continue;
if(A[i][k]+A[k][j]<A[i][j])
{
A[i][j]=A[i][k]+A[k][j];
path[i][j]=path[k][j];
}
}
}
}
但是这里我们要注意循环的嵌套顺序,如果把检查所有节点X放在最内层,那么结果将是不正确的,为什么呢?因为这样便过早的把i到j的最短路径确定下来了,而当后面存在更短的路径时,已经不再会更新了。
因此上段代码的循环嵌套才是正确的
三:算法的实现
在实现时,需要两个数组:
1:数组A:使用同一个数组A[i][j]开存放一系列的当前的A[i][j],初始时,A[i][j]=Edge[i][j],算法结束时A[i][j]就是vi与vj的最短路径长度
2:path数组:path[i][j]是从vi到vj的最短路径上顶点vj的前一个顶点的序号,主要用于路径的打印
四:具体代码
1:
void Floyd()
{
int i,j,k;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
A[i][j]=Edge[i][j];//对A[][]初始化
if(i!=j&&A[i][j]<INF)
path[i][j]=i;//i到j有路径
else
path[i][j]=-1;//i到j无路径
}
}
//从A(-1)递推到A(0)...A(n-1)
//或者理解成依次将v0,v1.....v(n-1)作为中间顶点
for(k=0;k<n;k++)
{
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(k==i||k==j)
continue;
if(A[i][k]+A[k][j]<A[i][j])
{
A[i][j]=A[i][k]+A[k][j];
path[i][j]=path[k][j];
}
}
}
}
}
2:主函数的情况
int main()
{
int i,j;
int u,v,w;
cin>>n;
for(i=0;i<n;i++)//处理接接矩阵
{
for(j=0;j<n;j++)
{
Edge[i][j]=INF;
}
}
for(i=0;i<n;i++)//方阵A的要求
{
Edge[i][i]=0;
}
while(1)
{
cin>>u>>v>>w;
if(u==-1&&v==-1&&w==-1)
break;
Edge[u][v]=w;
}
Floyd();
int shortest[MAXN];//从这开始就是为了打印路径
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(i==j)
continue;
cout<<i<<"=>"<<j<<'\t'<<A[i][j];
memset(shortest,0,sizeof(shortest));
int k=0;
shortest[k]=j;
while(path[i][shortest[k]]!=i)
{
k++;
shortest[k]=path[i][shortest[k-1]];
}
k++;
shortest[k]=i;
}
}
for(int t=k;t>0;t--)
cout<<shortest[t]<<"->";
cout<<shortest[0]<<endl;
return 0;
}
//求指教