弗洛伊德(Froyd)算法用于求解所有顶点到所有顶点的的最短路径。时间复杂度为O(n^3).

正如我们所知道的,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];}}}
}

如果还是看不懂,那就用草稿纸模拟一遍,之后你就会豁然开朗。半个小时足矣(早知道的话会节省很多个半小时了。。

如果是i-j-k这样的情况吧。举个例子:

如果我们现在要更新的1-4的最短距离,要枚举经过的城市个数,有0,1,2,3,4,5种情况,假如现在2-3城市的最短距离为10,当经过的城市为2时候,发现2-3的最短距离为10,可能比其他大了,所以经过2个城市的最小距离可能为8,上面6种情况更新后发现1-4最短距离为13.

当继续更新时,我们更新后2-3的最短距离竟然为1,但是我们再也回不到1-4这种情况了。。。所以,1-4的最短距离明显就是错误的。

而如果循环的顺序为:k-i-j的时候:

我们更新1-4的时候,2-3可能没更新,但是1-4可以更新k次,即使不是最短的,以后再更新到的时候就可以更新为最短了。所以这种才是正确的方法。

这样一来,对于每一个节点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)。

测试代码如下:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
#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];}}
}void floyd( int _arrDis[][MAX_VERTEX_COUNT], int _arrPath[][MAX_VERTEX_COUNT], int _nVertexCount )
{// 先初始化_arrPathfor ( 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];}}}}
}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();unsigned int 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()
{Graph myGraph;readGraphData( &myGraph );//int arrDis[MAX_VERTEX_COUNT][MAX_VERTEX_COUNT];int arrPath[MAX_VERTEX_COUNT][MAX_VERTEX_COUNT];// 先初始化arrDisfor ( 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 );//return 0;
}

转自:

Floyd算法详讲

弗洛伊德(Floyd)算法求解图的最短路径相关推荐

  1. Dijkstra算法求解图中最短路径距离

    前言:这里是自学内容,讲解的是用python来实现Dijkstra算法,算是入门求解图中最短路径问题的典型案例. 算法简介: 迪杰斯特拉(Dijkstra)算法是一个按照路径长度递增的次序产生的最短路 ...

  2. 数据结构与算法(7-4)最短路径(迪杰斯特拉(Dijkstra)算法、弗洛伊德(Floyd)算法)

    目录 一.最短路径概念 二.迪杰斯特拉(Dijkstra)算法(单源最短路径) 1.原理 2.过程 3.代码 三.弗洛伊德(Floyd)算法(多源最短路径) 1.原理 2.存储 3.遍历 4.代码 参 ...

  3. Floyd算法求解最短路径

    Floyd算法求解最短路径 1.算法概述 2.算法实例 3.算法实战 3.1 算法描述 3.2 解题思路 3.3 代码实现 1.算法概述   Floyd算法又称为插点法,是一种利用动态规划的思想寻找给 ...

  4. 060.弗洛伊德(Floyd)算法的原理以及解决最短路径问题

    1. 弗洛伊德(Floyd)算法的原理 1.1. 基本介绍 1.1.1. 弗洛伊德算法和迪杰斯特拉算法比较 1.2. 算法步骤 1.3. 步骤图解 1.3.1. 第一轮循环 1.3.2. 找出每个点作 ...

  5. floyd算法求解地铁路线问题

    题目描述Description 假设有两条地铁线路,1 号线为直线线路,2 号线为环线线路, 假设 1 号线的各个站点名称分别为 "A" "B" "C ...

  6. 算法其实很简单—弗洛伊德(Floyd)算法

    目录 1.弗洛伊德(Floyd)算法介绍 2.弗洛伊德(Floyd)算法最佳应用-最短路径 3.弗洛伊德(Floyd)算法图解分析 3.1 弗洛伊德算法的步骤: 4.代码实现 1.弗洛伊德(Floyd ...

  7. Java迪杰斯特拉(Dijkstra)算法与弗洛伊德(Floyd)算法

    1.Java迪杰斯特拉(Dijkstra)算法与弗洛伊德(Floyd)算法 1.1 迪杰斯特拉(Dijkstra)算法 1.1.1 迪杰斯特拉(Dijkstra)算法介绍 迪杰斯特拉(Dijkstra ...

  8. Java实现之弗洛伊德(Floyd)算法

    一.问题引入 1.问题引入 1)胜利乡有7个村庄(A,B,C,D,E,F, G) 2)各个村庄的距离用边线表示(权),比如A-B距离5公里3)问:如何计算出各村庄到其它各村庄的最短距离? 二.基本介绍 ...

  9. Floyd算法求解最短距离

    1.问题 用Floyd算法求解下图各个顶点的最短距离.写出Floyd算法的伪代码和给出距离矩阵(顶点之间的最短距离矩阵). 2.解析 Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权 ...

最新文章

  1. 印度小哥“神剑”:PDF提取表格so easy!
  2. windows域设计best practice
  3. 卓有成效的管理者应该借助哪些团队协作工具?
  4. 自动驾驶汽车“定位”技术
  5. 开闭操作进行平滑处理与边缘提取
  6. 特征工程(3):特征选择
  7. PAT乙类1007之素数对猜想
  8. 帝国 标签模板 使用程序代码 自定义 时间显示方式
  9. 【Tensorflow】深度学习实战06——Tensorflow实现ResNet
  10. 天梯赛L2-014 列车调度(set和简单贪心)
  11. SAP License:MIRO
  12. 辐射校正:像元DN值—辐照度—表观反射率—地表反射率
  13. 7的整除特征 三位一截_7的倍数特征
  14. js 禁止鼠标菜单键及键盘快捷键
  15. 网上商城的功能模块架构设计之(一)
  16. C语言程序设计现代方法第二版,第八章课后编程题——第9题生成贯穿10乘10字符组的随机步法
  17. android wifi 共享网络,手机与电脑之间共享网络的设置方法(Android无线网络共享设置指南)...
  18. c#调用触滑输入法实现触摸屏键盘功能
  19. SwiftUI系列教程第1章第4节:Text的Padding属性
  20. ElasticSerach 出现 high disk watermark [90%] exceeded on

热门文章

  1. 描述超宽带雷达的原理
  2. 快速傅里叶变换(FFT)算法学习
  3. 总结几个简单好用的Python人脸识别算法
  4. Spring Boot 官方文档中文版
  5. centos 7 升级 sudo
  6. 电脑删除的照片如何恢复
  7. 【linlong】Hutool工具,身份证号、手机号、姓名等数据脱敏信息工具类介绍
  8. VMware虚拟机黑屏解决
  9. 协议适配器错误的解决方法
  10. 微信小程序接入物流快递查询的接口API步骤