Floyd算法详讲

来源:互联网 发布:宝马5系改装轮毂数据 编辑:程序博客网 时间:2024/06/05 00:09

Floyd–Warshall(简称Floyd算法)是一种著名的解决任意两点间的最短路径(All Paris Shortest Paths,APSP)的算法。从表面上粗看,Floyd算法是一个非常简单的三重循环,而且纯粹的Floyd算法的循环体内的语句也十分简洁。我认为,正是由于“Floyd算法是一种动态规划(Dynamic Programming)算法”的本质,才导致了Floyd算法如此精妙。因此,这里我将从Floyd算法的状态定义、动态转移方程以及滚动数组等重要方面,来简单剖析一下图论中这一重要的基于动态规划的算法——Floyd算法。

Floyd算法的基本思想如下:从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从A到B,2是从A经过若干个节点X到B。所以,我们假设Dis(AB)为节点A到节点B的最短路径的距离,对于每一个节点X,我们检查Dis(AX) + Dis(XB) < Dis(AB)是否成立,如果成立,证明从A到X再到B的路径比A直接到B的路径短,我们便设置Dis(AB) = Dis(AX) + Dis(XB),这样一来,当我们遍历完所有节点X,Dis(AB)中记录的便是A到B的最短路径的距离。

来看看代码:

for ( int i = 0; k < 节点个数; ++i ){    for ( int j = 0; i < 节点个数; ++j )    {        for ( int k = 0; j < 节点个数; ++k )        {            if ( Dis[i][k] + Dis[k][j] < Dis[i][j] )            {                // 找到更短路径                Dis[i][j] = Dis[i][k] + Dis[k][j];            }        }    }}

Floyd算法本质上是DP,即对于每个(可能的)新增的节点k,来更新(可能的)节点i到j的最短距离。
那就有人要问了,为什么新增节点 k 的循环要放在最外层呢? 因为如果放到内层,这样便过早的把i到j的最短路径确定下来了,而当后面存在更短的路径时,已经不再会更新了。

用图来举个例子:
这里写图片描述
图中红色数字代表权值,如果我们在内层检查所有节点时,我们只能发现一条路径A->B,距离为9,显然这样是不正确的,正确的最短路径是A->D->C->B,路径距离为6。之所以这样就是因为把检查所有节点的循环放到了内层,造成了找到一条路径就过早的确定下来,而这一条路径不一定是最短路径。

如果还不明白,举个实例:

这里写图片描述

代码://Floyd#include<set>#include<queue>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>#define FOR(i,n,x) for(int i=x; i<=n; i++)#define Inf 1<<29using namespace std;int mp[100][100],n,m;int main(){    while(~scanf("%d%d",&n,&m)!=EOF)    {        FOR(i,n,1)        {            FOR(j,n,1)            {                if(i!=j)                    mp[i][j]=Inf;                    else mp[i][j]=0;            }        }        FOR(i,m,1)        {            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            mp[a][b]=c;        }        FOR(k,n,1)//枚举任意一对节点        {            FOR(i,n,1)//起点            {                FOR(j,n,1)//终点                {                    if(i!=j && j!=k)                    {                        mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);                    }                }            }        }        FOR(i,n,1)        {            FOR(j,n,1)            {                printf("dis %d %d = %d\n",i,j,mp[i][j]);            }        }    }    return 0;}

算法时间复杂度O(n3)

输入

4 41 4 14 2 34 3 13 2 1

输出

dis 1 1 = 0dis 1 2 = 3dis 1 3 = 2dis 1 4 = 1dis 2 1 = 536870912dis 2 2 = 0dis 2 3 = 536870912dis 2 4 = 536870912dis 3 1 = 536870912dis 3 2 = 1dis 3 3 = 0dis 3 4 = 536870912dis 4 1 = 536870912dis 4 2 = 2dis 4 3 = 1dis 4 4 = 0

Floyd算分的优缺点:
Floyd算法适用于APSP(All Pairs Shortest Paths,多源最短路径),是一种动态规划算法,稠密图效果最佳,边权可正可负。此算法简单有效,由于三重循环结构紧凑,对于稠密图,效率要高于执行|V|次Dijkstra算法,也要高于执行V次SPFA算法。
优点:容易理解,可以算出任意两个节点之间的最短距离,代码编写简单。
缺点:时间复杂度比较高,不适合计算大量数据
局限性:floyd算法可以有负权值的边,但不能有包含负权值边组成的回路

参考:

http://chenchuangfeng.iteye.com/blog/1816976
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html
http://blog.csdn.net/start0609/article/details/7779042
http://blog.csdn.net/niushuai666/article/details/6772706
http://nopainnogain.iteye.com/blog/1047818
http://blog.csdn.net/earbao/article/details/8114861
http://blog.csdn.net/roofalison/article/details/5651806

0 0