• 【算法】Floyd-Warshall算法(任意两点间的最短路问题)(判断负圈)


    问题

    求解任意两点间最短路问题也叫多源最短路径问题。

    可解决途径

    一种方法是把图中每个点当做源点重复算n次Dijkstra 算法(Dijkstra是求单源最短路径的算法),时间复杂度O(n^3),据说可以优化成O(n^2logn)。
    另一种方法时最经典的算法Floyd算法,时间复杂度也是O(n^3),但是关键代码只有5行,适合时间要求不苛刻的时候编写。

    Floyd算法基本思想

    Floyd算法本质上是一个动态规划算法。对于每个顶点k,枚举其他两个顶点i和j,若i和j之间的距离大于i到k加上k到j的距离,那么更新i到j之间的距离。

    【注】Floyd算法允许图中有带负权值的边,但不允许有包含带负权值的边组成的回路。(这句话摘自书上,本人并未深刻理解,若有大佬理解,望指教一二)

    基本操作

    d[k][i][j] 表示 顶点i 经过顶点k 到顶点j 的最短路径长度。

    分两种情况讨论:

    1. 经过顶点k, d[k][i][j] = d[k-1][i][j]。 即等于只用前k-1个顶点时的最短路径

    2. 不经过顶点k, d[k][i][j] = d[k-1][i][k] + d[k-1][k][j]。 即等于i离k的最路路径+k离j的最短路径。

    可以得到递推式 d[k][i][j] = min( d[k-1][i][j] , d[k-1][i][k] + d[k-1][s][k] );

    还可优化

    由于第k层只与k-1层相关,也可以用二维表示:

    (本图来自知乎,放在此处便于大家理解,侵删)
    d[i][j] = min( d[i][j] , d[i][k] + d[k][j] );

    精简版算法模板:

    #include <bitsstdc++.h>
    using namespace std;
    #define INF 2147483647
    #define MAX_V 1000
    #define MAX_E 2000 
    
    int d[MAX_V][MAX_V]; // d[u][v]表示边u->v的距离(不存在时设为INF,d[i][i] = 0) 
    int V;             //  顶点数 
    void warshall_floyd(){
        
        for(int k = 0;k < V; k++){
            for(int i = 0;i < V; i++){
                for(int j = 0;j < V; j++){
                    if(i != j && i != k && j != k)
                        if(d[i][k] != INF && d[k][j] != INF) //INF与正数相加会溢出
                            d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
                }
            }
        }
    }
    int main(){
    } 
    
  • 相关阅读:
    页面实现文件的下载
    微信小程序拉起登录的操作
    css3之border-radius理解
    web前端常用网站--更新中
    小程序中遇见文件过大的话就需要分包
    JS中的“&&”与“&”和“||”“|”有什么区别?
    ts中有时莫名报错
    浏览器解析JavaScript的原理
    在vue中axios的问题
    eslint的规则
  • 原文地址:https://www.cnblogs.com/zhangjiuding/p/11434467.html
Copyright © 2020-2023  润新知