问题的提出:已知一个有向网(或无向网),对每一对顶点(vi!=vj),要求求出vi和vj之间的最短路径和最短路径长度。
解决方法:(1)轮流以每个顶点为源点,重复执行Dijkstra算法或Bellman—Ford算法n次,就可以求出每一对顶点之间的最短路径和最短路径长度。总的时间复杂度为O(n^3)或O(n^2+ne);
(2)采用Floyd算法。时间复杂度与上述相同,但Floyd算法更直接。
算法思想:对一个顶点个数为n的有向网(或无向网),设置一个n*n的方阵A^(k),其中除对角线的矩阵元素都为0外,其他元素A^(k)[i][j] (i!=j)表示从顶点vi到顶点vj的最短路径长度,k表示运算步骤
初始时:以任意两个顶点之间的直接有向边权值作为最短路劲长度。对于任意两个顶点,若他们之间存在有向边,则以此边的权值作为它们之间的最短路径长度,若他们之间不存在有向边,则以无穷大作为他们之间的最短路径长度。
以后逐步尝试在原路径中加入其他顶点作为中间顶点,如果加入中间顶点后,得到的路径长度比原来的最短路径长度减少了则以此新路径代替原路径,修改矩阵元素,更新为更短的路径长度
A^(k)[i][j]表示从顶点vi到顶点vj的,中间顶点序号不大于k的最短路径长度。采用递推的方式计算A^(k)[i][j]. A^(n-1)[i][j]是最终求得的最短路径长度。
例题:求所有顶点之间的最短路径长度及其最短路径。
测试数据:
输入:
4
0 1 1
0 3 4
1 2 9
1 3 2
2 0 3
2 1 5
2 3 8
3 2 6
-1 -1 -1
输出:
0=>1 1 0-1
0=>2 9 0-1-3-2
0=>3 3 0-1-3
1=>0 11 1-3-2-0
1=>2 8 1-3-2
1=>3 2 1-3
2=>0 3 2-0
2=>1 4 2-0-1
2=>3 6 2-0-1-3
3=>0 9 3-2-0
3=>1 10 3-2-0-1
3=>2 6 3-2
#include<cstdio>
#include<iostream>
#include<cstring>
#define INF 0x3f3f3f3f
#define MAXN 8
using namespace std;
int map[MAXN][MAXN];
int A[MAXN][MAXN];
int path[MAXN][MAXN];
int n;
void Floyd()
{
int i,j,k;
for(i=0;i<n;i++)///对A[][]和path[][]进行初始化
{
for(j=0;j<n;j++)
{
A[i][j]=map[i][j];
if(i!=j&&A[i][j]<INF)
path[i][j]=i;
else
path[i][j]=-1;
}
}
for(k=0;k<n;k++)///加入v0时,判断能通过V0连接起来的点是否
{ /// 需要更新权值
for(i=0;i<n;i++)///加入V1时,判断能通过v1或v1,v0的点是否需要更新权值
{ ///加入V2时,判断能通过V2或V1,V2或V0,V1,V2的点是否需要
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];
}
}
}
}
}
int main()
{
int i,j;
int u,v,w;
scanf("%d",&n);
while(1)
{
scanf("%d%d%d",&u,&v,&w);
if(u==-1&&v==-1&&w==-1)
break;
map[u][v]=w;
}
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(i==j)
map[i][j]=0;
else if(map[i][j]==0)
map[i][j]=INF;
}
}
Floyd();
int shortest[MAXN];
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(i==j) continue;
printf("%d=>%d\t%d\t",i,j,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--)
printf("%d-",shortest[t]);
printf("%d\n",shortest[0]);
}
}
return 0;
}