zoukankan      html  css  js  c++  java
  • 【算法】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(){
    } 
    
  • 相关阅读:
    c# 动态加载工具栏按钮代码
    根据结果集处理工作事务c#源码
    关于升级后药库中报表需要重新设置的问题
    vs2005打开工程后退出
    把照片写入到DataTable
    关于导入最新住院管理后界面控件乱的问题
    django实战2运维日常维护统计
    ip_conntrack_netbios_n 报错
    django_book学习笔记7django常用方法总结
    python模块整理14re模版
  • 原文地址:https://www.cnblogs.com/zhangjiuding/p/11434467.html
Copyright © 2011-2022 走看看