Floyd-Warshall 算法用来找出每对点之间的最短距离。它需要用邻接矩阵来储存边,这个算法通过考虑最佳子路径来得到最佳路径。
注意单独一条边的路径也不一定是最佳路径。
- 从任意一条单边路径开始。所有两点之间的距离是边的权,或者无穷大,如果两点之间没有边相连。
- 对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是更新它。
- 不可思议的是,只要按排适当,就能得到结果
// dist(i,j) 为从节点i到节点j的最短距离 For i←1 to n do For j←1 to n do dist(i,j) = weight(i,j) For k←1 to n do // k为“媒介节点” For i←1 to n do For j←1 to n do if (dist(i,k) + dist(k,j) < dist(i,j)) then // 是否是更短的路径? dist(i,j) = dist(i,k) + dist(k,j)
这个算法的效率是O(V3)。它需要邻接矩阵来储存图。
这个算法很容易实现,只要几行。
即使问题是求单源最短路径,还是推荐使用这个算法,如果时间和空间允许(只要有放的下邻接矩阵的空间,时间上就没问题)。
一个演示的例子代码:
#include
<
stdio.h
>
#define NV 5
#define MA 9999999
int main( void )
{
int graph[NV][NV] =
{
0 , 1 , 7 , 2 , 8 ,
1 , 0 , 3 , 2 , 2 ,
7 , 3 , 0 , 4 , 4 ,
2 , 2 , 4 , 0 , 3 ,
8 , 2 , 4 , 3 , 0
};
int num = NV;
int path[NV][NV];
int i,j,k;
for (i = 0 ;i < num;i ++ ) {
for (j = 0 ;j < num;j ++ )
printf( " %d " ,graph[i][j]);
printf( " " );
}
for (i = 0 ;i < num;i ++ ) {
for (j = 0 ;j < num;j ++ ){
path[i][j] = graph[i][j];
}
}
for (k = 0 ;k < num;k ++ )
for (i = 0 ;i < num;i ++ )
for (j = 0 ;j < num;j ++ )
if (path[i][j] > graph[i][k] + graph[k][j])
path[i][j] = graph[i][k] + graph[k][j];
for (i = 0 ;i < num;i ++ )
{ for (j = 0 ;j < num;j ++ )
printf( " Shortest distance between <%d,%d>: %d " ,i + 1 ,j + 1 ,path[i][j]);
}
return 0 ;
}
#define NV 5
#define MA 9999999
int main( void )
{
int graph[NV][NV] =
{
0 , 1 , 7 , 2 , 8 ,
1 , 0 , 3 , 2 , 2 ,
7 , 3 , 0 , 4 , 4 ,
2 , 2 , 4 , 0 , 3 ,
8 , 2 , 4 , 3 , 0
};
int num = NV;
int path[NV][NV];
int i,j,k;
for (i = 0 ;i < num;i ++ ) {
for (j = 0 ;j < num;j ++ )
printf( " %d " ,graph[i][j]);
printf( " " );
}
for (i = 0 ;i < num;i ++ ) {
for (j = 0 ;j < num;j ++ ){
path[i][j] = graph[i][j];
}
}
for (k = 0 ;k < num;k ++ )
for (i = 0 ;i < num;i ++ )
for (j = 0 ;j < num;j ++ )
if (path[i][j] > graph[i][k] + graph[k][j])
path[i][j] = graph[i][k] + graph[k][j];
for (i = 0 ;i < num;i ++ )
{ for (j = 0 ;j < num;j ++ )
printf( " Shortest distance between <%d,%d>: %d " ,i + 1 ,j + 1 ,path[i][j]);
}
return 0 ;
}