Floyd算法用于求图中任意两点的最短距离。
Floyd算法的内涵是遍历N个结点,对于第k个结点,将k结点作为中间结点,更新其余结点的信息:即其余结点(i)能否通过结点k来缩短与其他结点(j)的距离。
Floyd的代码写起来非常简洁,但一直有一个小问题会困惑,假设i-j的最短距离中,以k结点更新最短距离时,如果此时i-k和k-j不是最短距离,如何保证i-j是最短距离呢?
假设i-j最短距离中,编号最大的中间结点是k,i-k中编号最大的结点是k1,k-j中是k2,那么k1,k2都小于k,可知在循环至结点k时,k1,k2都已经循环过了,那么i-k,k-j必定是最短距离。
代码:
#include <iostream>
#define MAX 999999
using namespace std;
const int n = 5;
int graph[n+1][n+1]={
{0, 0 , 0 , 0 , 0 , 0 },
{0, 0 , 3 , 5 , MAX, MAX },
{0, 3 , 0 , 10 , 4 , 1 },
{0, 5 , 10 , 0 , 5 , MAX },
{0, MAX, 4 , 5 , 0 , 1 },
{0, MAX, 1 , MAX, 1 , 0 }
};
int main()
{
int dis[n+1][n+1]; //结点 i到j的最短距离
int pre[n+1][n+1]; //结点 i到j的最短距离中 i的下一个结点
int i,j,k;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
dis[i][j] = graph[i][j];
pre[i][j] = j;
}
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(dis[k][j] != MAX && dis[i][j] > dis[i][k] + dis[k][j])
{
dis[i][j] = dis[i][k] + dis[k][j];
pre[i][j] = pre[i][k];
}
}
cout<<"最短距离"<<endl;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
cout<<dis[i][j]<<" ";
cout<<endl;
}
cout<<"路径"<<endl;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
cout<<pre[i][j]<<" ";
cout<<endl;
}
cout<<"输入结点i,j"<<endl;
cin>>i>>j;
cout<<i;
while(pre[i][j] != j)
{
cout<<"-"<<pre[i][j];
i = pre[i][j];
}
cout<<"-"<<j;
return 0;
}
这里解释一下pre数组,pre[i][j]表示i-j结点中i的下一结点.
初始化时,pre[i][j] = j 即默认i-j都有通路,所以下一结点就是j
循环至结点k时,若通过了结点k来更新时,则pre[i][j] = pre[i][k],即i到j的中,i与k中,使i的下一结点相同。
i到j的最短距离中包含了i到k这么一段。