http://www.cnblogs.com/twjcnblog/archive/2011/09/07/2170306.html

正如我们所知道的,Floyd算法用于求最短路径。Floyd算法可以说是Warshall算法的扩展,三个for循环就可以解决问题,所以它的时间复杂度为O(n^3)。

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

但是这里我们要注意循环的嵌套顺序,如果把检查所有节点X放在最内层,那么结果将是不正确的,为什么呢?因为这样便过早的把i到j的最短路径确定下来了,而当后面存在更短的路径时,已经不再会更新了。

让我们来看一个例子,看下图:

图中红色的数字代表边的权重。如果我们在最内层检查所有节点X,那么对于A->B,我们只能发现一条路径,就是A->B,路径距离为9。而这显然是不正确的,真实的最短路径是A->D->C->B,路径距离为6。造成错误的原因就是我们把检查所有节点X放在最内层,造成过早的把A到B的最短路径确定下来了,当确定A->B的最短路径时Dis(AC)尚未被计算。所以,我们需要改写循环顺序,如下:

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

这样一来,对于每一个节点X,我们都会把所有的i到j处理完毕后才继续检查下一个节点。

那么接下来的问题就是,我们如何找出最短路径呢?这里需要借助一个辅助数组Path,它是这样使用的:Path(AB)的值如果为P,则表示A节点到B节点的最短路径是A->...->P->B。这样一来,假设我们要找A->B的最短路径,那么就依次查找,假设Path(AB)的值为P,那么接着查找Path(AP),假设Path(AP)的值为L,那么接着查找Path(AL),假设Path(AL)的值为A,则查找结束,最短路径为A->L->P->B。

那么,如何填充Path的值呢?很简单,当我们发现Dis(AX) + Dis(XB) < Dis(AB)成立时,就要把最短路径改为A->...->X->...->B,而此时,Path(XB)的值是已知的,所以,Path(AB) = Path(XB)。

好了,基本的介绍完成了,接下来就是实现的时候了,这里我们使用图以及邻接矩阵:

#define
INFINITE 1000           // 最大值
#define
MAX_VERTEX_COUNT 20   // 最大顶点个数
//////////////////////////////////////////////////////////////////////////


struct Graph
{
    int     arrArcs[MAX_VERTEX_COUNT][MAX_VERTEX_COUNT];   //
邻接矩阵
    int     nVertexCount;                              
  
//
顶点数量
    int     nArcCount;                                 
  
//
边的数量
};
//////////////////////////////////////////////////////////////////////////

首先,我们写一个方法,用于读入图的数据:

void readGraphData(
Graph *_pGraph )
{
    std::cout
<<
"请输入顶点数量和边的数量:
"
;
    std::cin
>> _pGraph->nVertexCount;
    std::cin
>> _pGraph->nArcCount;
 
    std::cout
<<
"请输入邻接矩阵数据:" <<
std::endl;
    for (int row
= 0; row < _pGraph->nVertexCount; ++row )
    {
        for (int col
= 0; col < _pGraph->nVertexCount; ++col )
        {
            std::cin
>> _pGraph->arrArcs[row][col];
        }
    }
}

接着,就是核心的Floyd算法:

void floyd(int _arrDis[][MAX_VERTEX_COUNT],int _arrPath[][MAX_VERTEX_COUNT],int _nVertexCount
)
{
    //
先初始化_arrPath
    for (int i
= 0; i < _nVertexCount; ++i )
    {
        for (int j
= 0; j < _nVertexCount; ++j )
        {
            _arrPath[i][j]
= i;
        }
    }
    //////////////////////////////////////////////////////////////////////////
 
    for (int k
= 0; k < _nVertexCount; ++k )
    {
        for (int i
= 0; i < _nVertexCount; ++i )
        {
            for (int j
= 0; j < _nVertexCount; ++j )
            {
                if (
_arrDis[i][k] + _arrDis[k][j] < _arrDis[i][j] )
                {
                    //
找到更短路径
                    _arrDis[i][j]
= _arrDis[i][k] + _arrDis[k][j];
 
                    _arrPath[i][j]
= _arrPath[k][j];
                }
            }
        }
    }
}

OK,最后是输出结果数据代码:

void printResult(int _arrDis[][MAX_VERTEX_COUNT],int _arrPath[][MAX_VERTEX_COUNT],int _nVertexCount
)
{
    std::cout
<<
"Origin
-> Dest   Distance    Path"
 <<
std::endl;
 
    for (int i
= 0; i < _nVertexCount; ++i )
    {
        for (int j
= 0; j < _nVertexCount; ++j )
        {
            if (
i != j )  
//
节点不是自身
            {
                std::cout
<< i+1 <<
"
-> "
 <<
j+1 <<
"\t\t";
                if (
INFINITE == _arrDis[i][j] )   
//
i -> j 不存在路径
                {
                    std::cout
<<
"INFINITE" <<"\t\t";
                }
                else
                {
                    std::cout
<< _arrDis[i][j] <<
"\t\t";
 
                    //
由于我们查询最短路径是从后往前插,因此我们把查询得到的节点
                    //
压入栈中,最后弹出以顺序输出结果。
                    std::stack<int>
stackVertices;
                    int k
= j;
                     
                    do
                    {
                        k
= _arrPath[i][k];
                        stackVertices.push(
k );
                    }while (
k != i );
                    //////////////////////////////////////////////////////////////////////////
 
                    std::cout
<< stackVertices.top()+1;
                    stackVertices.pop();
 
                    unsignedint nLength
= stackVertices.size();
                    for (
unsigned
int nIndex
= 0; nIndex < nLength; ++nIndex )
                    {
                        std::cout
<<
"
-> "
 <<
stackVertices.top()+1;
                        stackVertices.pop();
                    }
 
                    std::cout
<<
"
-> "
 <<
j+1 << std::endl;
                }
            }
        }
    }
}

好了,是时候测试了,我们用的图如下:

测试代码如下:

int main(void )
{
    Graph
myGraph;
    readGraphData(
&myGraph );
    //////////////////////////////////////////////////////////////////////////
 
    int arrDis[MAX_VERTEX_COUNT][MAX_VERTEX_COUNT];
    int arrPath[MAX_VERTEX_COUNT][MAX_VERTEX_COUNT];
 
    //
先初始化arrDis
    for (int i
= 0; i < myGraph.nVertexCount; ++i )
    {
        for (int j
= 0; j < myGraph.nVertexCount; ++j )
        {
            arrDis[i][j]
= myGraph.arrArcs[i][j];
        }
    }
 
    floyd(
arrDis, arrPath, myGraph.nVertexCount );
    //////////////////////////////////////////////////////////////////////////
 
    printResult(
arrDis, arrPath, myGraph.nVertexCount );
    //////////////////////////////////////////////////////////////////////////
 
    system("pause" );
    return 0;
}

如图:

版权声明:本文为博主原创文章,未经博主允许不得转载。

Floyd算法(原理|代码实现)的更多相关文章

  1. Floyd算法核心代码证明

    Flody  大家都知道这个最终模版: for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dis[i ...

  2. 最短路-SPFA算法&Floyd算法

    SPFA算法 算法复杂度 SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环. SPFA一般情况复杂度是O(m)最坏情况下复杂度和朴素 ...

  3. 最短路径(Floyd算法)

    声明:图片及内容基于https://www.bilibili.com/video/BV1oa4y1e7Qt?from=articleDetail 多源最短路径的引入 Floyd算法 原理 加入a: 加 ...

  4. (poj 3660) Cow Contest (floyd算法+传递闭包)

    题目链接:http://poj.org/problem?id=3660 Description N ( ≤ N ≤ ) cows, conveniently numbered ..N, are par ...

  5. HDOJ 1217 Arbitrage(拟最短路,floyd算法)

    Arbitrage Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total ...

  6. Floyd算法简单实现(C++)

    图的最短路径问题主要包括三种算法: (1)Dijkstra (没有负权边的单源最短路径) (2)Floyed (多源最短路径) (3)Bellman (含有负权边的单源最短路径) 本文主要讲使用C++ ...

  7. 图的最短路径算法-- Floyd算法

    Floyd算法求的是图的任意两点之间的最短距离 下面是Floyd算法的代码实现模板: ; ; // maxv为最大顶点数 int n, m; // n 为顶点数,m为边数 int dis[maxv][ ...

  8. Logistic回归分类算法原理分析与代码实现

    前言 本文将介绍机器学习分类算法中的Logistic回归分类算法并给出伪代码,Python代码实现. (说明:从本文开始,将接触到最优化算法相关的学习.旨在将这些最优化的算法用于训练出一个非线性的函数 ...

  9. AC-BM算法原理与代码实现(模式匹配)

    AC-BM算法原理与代码实现(模式匹配) AC-BM算法将待匹配的字符串集合转换为一个类似于Aho-Corasick算法的树状有限状态自动机,但构建时不是基于字符串的后缀而是前缀.匹配 时,采取自后向 ...

随机推荐

  1. 简述对Vuex的理解

          1.什么是Vuex:             Vuex是一个专为Vue.js应用程序开发的状态管理模式.     2.使用Vuex的原因:             当我们遇到多个组件共享状 ...

  2. PhpStorm 全局查找的快捷键

    本页面查找 :   ctrl  + f 全局查找 : ctrl + shift + f 自己定义 :文件 -> 设置  -> 快捷键  ->  修改

  3. 关于uip中的log和打印

    简单易用,好区分 void uip_log(char *m){ printf("uIP log message: %s\n", m);}

  4. Python中各种进制之间的转化

    1.十进制转化为其它进制 (1)bin(x):十进制转化为二进制 [实例1] x=bin(20)   # x的值为字符串'0b10100' (2)oct(x):十进制转化为八进制 [实例2] x=oc ...

  5. css3动画性能优化--针对移动端卡顿问题

    一.使用css,jquery,canvas制作动画 1.Canvas 优点:性能好,强大,支持多数浏览器(除了IE6.IE7.IE8),画出来的图形可以直接保存为 .png 或者 .jpg的图形: 缺 ...

  6. flink 根据时间消费kafka

    经常遇到这样的场景,13点-14点的时候flink程序发生了故障,或者集群崩溃,导致实时程序挂掉1小时,程序恢复的时候想把程序倒回13点或者更前,重新消费kafka中的数据. 下面的代码就是根据指定时 ...

  7. 20155236 2016-2017-2 《Java程序设计》第三周学习总结

    20155236 2016-2017-2 <Java程序设计>第三周学习总结 教材学习内容总结 1.在原始码中只能有一个公开类,且主文档名必须与公开类名称相同:其实只要有一个类定义,就会产 ...

  8. 20155305乔磊2016-2017-2《Java程序设计》第十周学习总结

    20155305乔磊2016-2017-2<Java程序设计>第十周学习总结 教材学习内容总结 Java的网络编程 网络编程 网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据. ...

  9. 20155327 2016-2017-2 《Java程序设计》第一周学习总结

    20155327 2016-2017-2 <Java程序设计>第一周学习总结 教材学习内容总结 浏览教材,根据自己的理解每章提出一个问题 1.JAVA SE中JVM,JRE与JDK分别是什 ...

  10. 【LOJ4632】[PKUSC2018]真实排名

    [LOJ4632][PKUSC2018]真实排名 题面 终于有题面啦!!! 题目描述 小 C 是某知名比赛的组织者,该比赛一共有 \(n\) 名选手参加,每个选手的成绩是一个非负整数,定义一个选手的排 ...