当前位置: 首页 > news >正文

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算法

正如我们所知道的&#xff0c;Floyd算法用于求最短路径。Floyd算法可以说是Warshall算法的扩展&#xff0c;三个for循环就可以解决问题&#xff0c;所以它的时间复杂度为O(n^3)。 Floyd算法的基本思想如下&#xff1a;从任意节点A到任意节点B的最短路径不外乎2种可能&#xff…...

SpringBoot究竟应该如何学习?

如果你有Spring的基础&#xff0c;学习Spring Boot就很简单了。 首先要知道Spring Boot是建立在Spring框架之上的&#xff0c;它旨在简化和加速Java应用程序的开发过程。 Spring Boot的目标是简化Spring应用程序的配置和开发&#xff0c;通过提供自动配置、快速开发和零配置的…...

为什么很多人认为ChatGPT最好的替代工具是Claude?

ChatGPT引领着生成式AI聊天机器人领域&#xff0c;但Claude AI看起来是一个有力的竞争者。 前段时间&#xff0c;ChatGPT的强劲竞争对手Claude2面世。当时很多人认为它可能会取代ChatGPT&#xff0c;在体验过一段时间之后&#xff0c;深以为然。原因如下&#xff1a; 更强大的…...

学习Vue:简介和优势

什么是 Vue.js&#xff1f; Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架。它专注于视图层&#xff0c;并且可以轻松地集成到现有的项目中。Vue.js 的设计理念是渐进式&#xff0c;这意味着您可以根据项目的需要逐步引入 Vue.js&#xff0c;从而更好地控制应用的复…...

***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信号槽主要分两个连接方式&#xff0c;手动和自动&#xff1a; 1.1 使用 connect() 函数手动连接信号和槽&#xff1a; QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot())); 自动&#xff1a; 1.2 使用 lambda 表达式连接信号和槽&#xff1a; connect(s…...

【yml文件的解释】

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

ChatGPT or BingChat

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

QT 使用第三方库QtXlsx操作Excel表

1.简介 一直以来&#xff0c;都想学习一下C/C如何操作excel表&#xff0c;在网上调研了一下&#xff0c;觉得使用C/C去操作很麻烦&#xff0c;遂转向QT这边&#xff1b;QT有一个自带的类QAxObject&#xff0c;可以使用他去操作&#xff0c;但随着了解的深入&#xff0c;觉得他…...

警惕网络个人技术人员:隐藏代码风险的启示

在当今数字化时代&#xff0c;我们对网络上个人技术人员的需求日益增加&#xff0c;这使得技术服务成为一项不可或缺的资源。然而&#xff0c;我最近的经历却引发了我对这种服务可靠性的怀疑&#xff0c;特别是当这些个人技术人员没有正式公司背景&#xff0c;缺乏可信的运营保…...

VBA 学习笔记1 对象以及属性

目录 1 取得VBA对象1.1 取得工作簿对象1.2 取得工作表对象1.3 取得单元格对象1.4 取得对象的属性1.5 文档的方法1 进入vba 界面 方式之一&#xff1a; 快捷键&#xff1a;ALTERF11 运行方式之一&#xff1a; 进入vba界面&#xff0c;点击绿色三角符号 1 取得VBA对象 1.1 取得…...

netty核心组件以及实现原理

Netty核心组件 网络通信层&#xff1a;这一层有三个核心组件&#xff1a;Bootstrap、ServerBootStrap和Channel。Bootstrap负责客户端的启动&#xff0c;并用来链接远程Netty Server&#xff1b;ServerBootStrap负责服务端监听&#xff0c;用来监听指定端口&#xff1b;Channe…...

如何正确下载tomcat???

亲爱的小伙伴&#xff0c;千万别再去找下网站下载啦&#xff0c;这样詪容易携带病毒。 我们去官方网址下载。 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&#xff08;消息队列遥测传输协议&#xff09;&#xff0c;是一种基于发布/订阅&#xff08;publish/subscribe&#xff09;模式的“轻量级”通讯协议&#xff0c;该协议构建于TCP/IP协…...

【前端】CSS水平居中的6种方法

文章目录 flex绝对定位margin:auto绝对定位margin:负值定位transformtext-align: center;margin: 0 auto;思维导图 后文&#xff1a;【前端】CSS垂直居中的7种方法_karshey的博客-CSDN博客 左右两边间隔相等的居中 flex display: flex;justify-content: center; <div clas…...

nginx如何获取真实的ip

我这里使用是springboot项目&#xff0c;使用nginx做代理&#xff0c;但header里面的参数没有将ip带过来&#xff0c;所有需要配置nginx将ip带过来。 nginx.conf文件 server {listen 80;listen 443 ssl;server_name xxx.xxx.com;ssl_certificate /web/project/ai…...

kotlin + LiveData 测试

viewModel测试&#xff1a;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的码友们&#xff0c;距离上一次我发文章已经过去了半年的时间&#xff0c;现在我又来介绍自己新发现和探究的开源技术了。计算机的发展总是飞速的&#xff0c;当我在写这篇文章的时候&#xff0c;Fedora rawhide已经进入了40版本、默认采用的自动化包管理器为dnf…...

数据可视化工具的三大类报表制作流程分享

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

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...