Floyd-Warshall--多源最短路算法

文章目录

  • 前言
  • 原理
  • 实现

前言

我们之前介绍过 D i j k s t r a Dijkstra Dijkstra B e l l m a n − F o r d / S P F A Bellman-Ford/SPFA BellmanFord/SPFA算法,这些算法解决的都是单源最短路的问题,那么有没有一个算法,可以计算出任意两点之间的最短路呢?答案是– F l o y d − W a r s h a l l Floyd-Warshall FloydWarshall.

原理

和所有最短路算法一样, F l o y d − W a r s h a l l Floyd-Warshall FloydWarshall算法也需要借助边的"松弛"操作来缩短最短路径,不同的是,对于每一条边, F l o y d − W a r s h a l l Floyd-Warshall FloydWarshall试图用剩余的所有顶点作为中间点去松弛,这样得到的就会是任意两点间的最短路径.关于这个算法的正确性,简单说明一下:

  1. 假设两个点之间没有边,通过中间点建立一条边,显然这两点的最短路缩短了;
  2. 假设两个点有边,通过若干个中间点缩短了最短路径,则设该图含有 V V V个顶点,可得两点之间最多通过 V − 2 V-2 V2个中间点缩短最短路径,此时路径包含 V − 1 V-1 V1条边,显然在不包含负环的图中,最短路不可能包括比这更多的边数,因此最多通过 V − 2 V-2 V2个点松弛;
  3. 在图中若存在负环,则2不成立,但此时也会不存在最短路径,因此在有解的情况下1,2始终正确.

F l o y d − W a r s h a l l Floyd-Warshall FloydWarshall的执行过程如下(来源:啊哈算法):

Floyd-Warshall--多源最短路算法_第1张图片

实现

F l o y d − W a r s h a l l Floyd-Warshall FloydWarshall算法通过邻接矩阵可以简单地实现:

#include
#define maxn 10000
#define inf 0x3f3f3f3f
using namespace std;

int e[maxn][maxn];

void init(int n) {
    for(int i = 0; i <= n; i++) {
        for(int j = 0; j <= n; j++) {
            if(i == j)
                e[i][j] = 0;
            else
                e[i][j] = inf;
        }
    }
}

void Floyd_Warshall(int n) {
    for(int k = 0; k <= n; k++) {
        for(int i = 0; i <= n; i++) {
            for(int j = 0; j <= n; j++) {
                e[i][j] = min(e[i][j],e[i][k]+e[k][j]);
            }
        }
    }
}

int main() {
    int n,m,u,v,w;
    while(cin>>n>>m) {
        init(n);
        for(int i = 0; i < m; i++) {
            cin>>u>>v>>w;
            e[u][v] = w;
// e[v][u] = w; //无向图;
        }
        Floyd_Warshall(n);
        for(int i = 0; i <= n; i++) { //输出最短路;
            for(int j = 0; j <=n ;j++) {
                cout<<e[i][j]<<" ";
            }
            cout<<endl;
        }
    }
    return 0;
}

因为要方便查询到任意两点之间的所有边,所以 F l o y d − W a r s h a l l Floyd-Warshall FloydWarshall算法最理想的实现方式就是邻接矩阵,如果要用邻接表实现,需要有两个邻接表,一个是入边表,一个是出边表,并且要维护每一个公共中间点的入边和出边的关系,这样的写法不但复杂,而且没有意义,时间和空间都没有太大的提升,因此只介绍邻接矩阵实现.

显然, F l o y d − W a r s h a l l Floyd-Warshall FloydWarshall的时间复杂度是 O ( V 3 ) O(V^3) O(V3),这是一个很高的时间复杂度,但是考虑到求得任意两点之间的最短路径,这个时间复杂度是可以接受的.

你可能感兴趣的:(ACM,数据结构,图论,算法)