Floyd算法
正如我们所知道的,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 ){// 先初始化_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];}}}}}
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();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( void ){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 );//system( "pause" );return 0;}
如图:
相关文章:

Floyd算法
正如我们所知道的,Floyd算法用于求最短路径。Floyd算法可以说是Warshall算法的扩展,三个for循环就可以解决问题,所以它的时间复杂度为O(n^3)。 Floyd算法的基本思想如下:从任意节点A到任意节点B的最短路径不外乎2种可能ÿ…...
SpringBoot究竟应该如何学习?
如果你有Spring的基础,学习Spring Boot就很简单了。 首先要知道Spring Boot是建立在Spring框架之上的,它旨在简化和加速Java应用程序的开发过程。 Spring Boot的目标是简化Spring应用程序的配置和开发,通过提供自动配置、快速开发和零配置的…...

为什么很多人认为ChatGPT最好的替代工具是Claude?
ChatGPT引领着生成式AI聊天机器人领域,但Claude AI看起来是一个有力的竞争者。 前段时间,ChatGPT的强劲竞争对手Claude2面世。当时很多人认为它可能会取代ChatGPT,在体验过一段时间之后,深以为然。原因如下: 更强大的…...
学习Vue:简介和优势
什么是 Vue.js? Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架。它专注于视图层,并且可以轻松地集成到现有的项目中。Vue.js 的设计理念是渐进式,这意味着您可以根据项目的需要逐步引入 Vue.js,从而更好地控制应用的复…...
***is not a commit and a branch ‘***‘ cannot be created from it 报错
git执行如下代码 git checkout -b daily/1.0.0 origin/daily/1.0.0遇到报错 fatal: ‘origin/daily/1.0.27’ is not a commit and a branch ‘daily/1.0.27’ cannot be created from it 解决办法: git fetch --all原因: 报错说is not a commit而不是说branch doesn’t exis…...
QT信号槽连接方式
1.QT信号槽主要分两个连接方式,手动和自动: 1.1 使用 connect() 函数手动连接信号和槽: QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot())); 自动: 1.2 使用 lambda 表达式连接信号和槽: connect(s…...

【yml文件的解释】
目录 一、yml的简介二、手写yml文件进行配置三、使用yaml格式导出生成模板四、deployment.yaml文件详解五、Pod yaml文件详解六、Service yaml文件详解 一、yml的简介 Kubernetes 支持 YAML 和 JSON 格式管理资源对象 JSON 格式:主要用于 api 接口之间消息的传递 Y…...

ChatGPT or BingChat
你相信我们对大模型也存在「迷信权威」吗? ChatGPT 的 GPT-4 名声在外,我们就不自觉地更相信它,优先使用它。但我用 ChatALL 比较 AI 大模型们这么久,得到的结论是: ChatGPT GPT-4 在大多数情况下确实是最强…...

QT 使用第三方库QtXlsx操作Excel表
1.简介 一直以来,都想学习一下C/C如何操作excel表,在网上调研了一下,觉得使用C/C去操作很麻烦,遂转向QT这边;QT有一个自带的类QAxObject,可以使用他去操作,但随着了解的深入,觉得他…...
警惕网络个人技术人员:隐藏代码风险的启示
在当今数字化时代,我们对网络上个人技术人员的需求日益增加,这使得技术服务成为一项不可或缺的资源。然而,我最近的经历却引发了我对这种服务可靠性的怀疑,特别是当这些个人技术人员没有正式公司背景,缺乏可信的运营保…...

VBA 学习笔记1 对象以及属性
目录 1 取得VBA对象1.1 取得工作簿对象1.2 取得工作表对象1.3 取得单元格对象1.4 取得对象的属性1.5 文档的方法1 进入vba 界面 方式之一: 快捷键:ALTERF11 运行方式之一: 进入vba界面,点击绿色三角符号 1 取得VBA对象 1.1 取得…...
netty核心组件以及实现原理
Netty核心组件 网络通信层:这一层有三个核心组件:Bootstrap、ServerBootStrap和Channel。Bootstrap负责客户端的启动,并用来链接远程Netty Server;ServerBootStrap负责服务端监听,用来监听指定端口;Channe…...

如何正确下载tomcat???
亲爱的小伙伴,千万别再去找下网站下载啦,这样詪容易携带病毒。 我们去官方网址下载。 Apache Tomcat - Welcome! 最后下载解压即可。。。...

mybatis-plus 根据指定字段 批量 删除/修改
mybatis-plus 提供了根据id批量更新和修改的方法,这个大家都不陌生 但是当表没有id的时候怎么办 方案一: 手写SQL方案二: 手动获取SqlSessionTemplate 就是把mybatis plus 干的事自己干了方案三 : 重写 executeBatch 方法结论: mybatis-plus 提供了根据id批量更新和修改的方法,…...

MQTT宝典
文章目录 1.介绍2.发布和订阅3.MQTT 数据包结构4.Demo5.EMQX 1.介绍 什么是MQTT协议 MQTT(消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的“轻量级”通讯协议,该协议构建于TCP/IP协…...

【前端】CSS水平居中的6种方法
文章目录 flex绝对定位margin:auto绝对定位margin:负值定位transformtext-align: center;margin: 0 auto;思维导图 后文:【前端】CSS垂直居中的7种方法_karshey的博客-CSDN博客 左右两边间隔相等的居中 flex display: flex;justify-content: center; <div clas…...
nginx如何获取真实的ip
我这里使用是springboot项目,使用nginx做代理,但header里面的参数没有将ip带过来,所有需要配置nginx将ip带过来。 nginx.conf文件 server {listen 80;listen 443 ssl;server_name xxx.xxx.com;ssl_certificate /web/project/ai…...
kotlin + LiveData 测试
viewModel测试:https://developer.android.com/codelabs/basic-android-kotlin-compose-test-viewmodel#3 androidTestImplementation "org.jetbrains.kotlin:kotlin-test:1.9.0"androidTestImplementation org.jetbrains.kotlinx:kotlinx-coroutines-tes…...

【dnf5文档】新一代RedHat自动化包管理器
前言 HI,CSDN的码友们,距离上一次我发文章已经过去了半年的时间,现在我又来介绍自己新发现和探究的开源技术了。计算机的发展总是飞速的,当我在写这篇文章的时候,Fedora rawhide已经进入了40版本、默认采用的自动化包管理器为dnf…...

数据可视化工具的三大类报表制作流程分享
电脑(pc)、移动、大屏三大类型的BI数据可视化报表制作步骤基本相同,差别就在于尺寸调整和具体的报表布局。这对于采用点击、拖拉拽方式来制作报表的奥威BI数据可视化工具来说就显得特别简单。接下来,我们就一起看看不这三大类型的…...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...