数据结构 —— FloydWarshall算法

数据结构 —— FloydWarshall算法

  • FloydWarshall算法
  • 三种最短路径算法比较
      • 1. Dijkstra算法
      • 2. Bellman-Ford算法
      • 3. Floyd-Warshall算法
      • 总结

我们之前介绍的两种最短路径算法都是单源最短路径,就是我们要指定一个起点来寻找最短路径,而我们今天介绍的FloydWarshall算法,可以不指定源点,找到最短路径:

FloydWarshall算法

在介绍FloydWarshall算法之前,我们先来想一个问题,就是:最短路径要经过多少顶点呢?
在这里插入图片描述第一种情况他俩之间就是最短距离
在这里插入图片描述
第二种,中间经过了许多结点
在这里插入图片描述在这里插入图片描述
Floyd-Warshall算法是一种在有向图中寻找所有顶点对之间的最短路径的算法。它可以在图中包含负权边的情况下工作,但是图中不能包含负权循环。

以下是Floyd-Warshall算法的基本步骤:

  1. 初始化:创建一个n×n的距离矩阵D,其中D[i][j]表示从顶点i到顶点j的最短路径的长度。如果(i,j)之间没有直接的边,则D[i][j]设置为无穷大。对于所有的顶点i,D[i][i]=0。
  1. 对于每一个中间顶点k,更新距离矩阵D。具体来说,对于每一对顶点(i, j),如果D[i][j] > D[i][k] + D[k][j],则更新D[i][j]为D[i][k] + D[k][j]。这相当于检查是否可以通过k作为中间顶点来获得从i到j的更短路径。
  1. 重复步骤2,直到所有可能的中间顶点都被考虑过。
  1. 最后,距离矩阵D中的每个元素D[i][j]将包含从顶点i到顶点j的最短路径的长度
void FloydWarshall(vector<vector<W>>& vvDest, vector<vector<int>>& vvParentpath)
{
    // 调整vvDest和vvParentpath的大小与顶点数量一致
    vvDest.resize(_vertex.size());
    vvParentpath.resize(_vertex.size());

    // 初始化距离矩阵为最大权重(表示不可达)
    // 初始化前驱节点矩阵为-1(表示无前驱节点)
    for (size_t i = 0; i < _vertex.size(); i++)
    {
        vvDest[i].resize(_vertex.size(), MAX_W);
        vvParentpath[i].resize(_vertex.size(), -1);
    }

    // 初始化距离矩阵和前驱节点矩阵
    // 如果两个顶点间存在直接连接,则设置距离矩阵的相应位置为该连接的权重
    // 并且设置前驱节点为当前顶点
    for (size_t i = 0; i < _vertex.size(); i++)
    {
        for (size_t j = 0; j < _vertex.size(); j++)
        {
            // 同一顶点到自身的距离为0,前驱节点为-1
            if (i == j)
            {
                vvDest[i][j] = 0;
                vvParentpath[i][j] = -1;
            }

            // 如果两顶点之间有直接连接,并且权重不是最大权重(即可达)
            if (_matrix[i][j] != MAX_W)
            {
                vvDest[i][j] = _matrix[i][j];
                vvParentpath[i][j] = i;
            }
            else
            {
                // 如果两顶点之间不可达,前驱节点为-1
                vvParentpath[i][j] = -1;
            }
        }
    }

    // 这里是核心部分,遍历所有顶点作为中间顶点,以检查是否存在更短路径
    for (size_t k = 0; k < _vertex.size(); k++)
    {
        for (size_t i = 0; i < _vertex.size(); i++)
        {
            for (size_t j = 0; j < _vertex.size(); j++)
            {
                // 如果存在通过顶点k作为中间顶点的更短路径,则更新距离和前驱节点
                if (vvDest[i][k] != MAX_W && vvDest[k][j] != MAX_W && vvDest[i][k] + vvDest[k][j] < vvDest[i][j])
                {
                    vvDest[i][j] = vvDest[i][k] + vvDest[k][j];
                    vvParentpath[i][j] = vvParentpath[k][j];
                }
            }
        }

        // 打印每次迭代后的距离矩阵和前驱节点矩阵(可选)
        				//打印权值和路径矩阵观察数据
				//cout << "     ";
				//for (size_t i = 0; i < _vertex.size(); i++)
				//{
				//	cout << _vertex[i] << " ";
				//}
				//cout << endl;

				for (size_t i = 0; i < _vertex.size(); ++i)
				{
					cout << _vertex[i] << " ";
					for (size_t j = 0; j < _vertex.size(); ++j)
					{
						if (vvDest[i][j] == MAX_W)
						{
							//cout << "*" << " ";
							printf("%3c", '*');
						}
						else
						{
							//cout << vvDest[i][j] << " ";
							printf("%3d", vvDest[i][j]);
						}
					}
					cout << endl;
				}

				cout << endl;
				for (size_t i = 0; i < _vertex.size(); ++i)
				{
					for (size_t j = 0; j < _vertex.size(); ++j)
					{
						//cout << vvParentPath[i][j] << " ";
						printf("%3d", vvParentpath[i][j]);
					}
					cout << endl;
				}
				cout << "=================================" << endl;
			}
    }
}

我们构建这样的图:
在这里插入图片描述

	void TestFloydWarshall()
	{
		const char* str = "12345";
		Graph<char, int, INT_MAX, true> g(str, strlen(str));
		g.AddEdge('1', '2', 3);
		g.AddEdge('1', '3', 8);
		g.AddEdge('1', '5', -4);
		g.AddEdge('2', '4', 1);
		g.AddEdge('2', '5', 7);
		g.AddEdge('3', '2', 4);
		g.AddEdge('4', '1', 2);
		g.AddEdge('4', '3', -5);
		g.AddEdge('5', '4', 6);
		vector<vector<int>> vvDist;
		vector<vector<int>> vvParentPath;
		g.FloydWarshall(vvDist, vvParentPath);
	}

在这里插入图片描述
大家可以对应一下上面的图,这里注意一下,我们的路径的数组存储的是下标,所以每组的第二个图比上图中的数值小1,这是正常的。

我们可以把每个结点到其他结点的最短路径打印出来:

	void TestFloydWarshall()
	{
		const char* str = "12345";
		Graph<char, int, INT_MAX, true> g(str, strlen(str));
		g.AddEdge('1', '2', 3);
		g.AddEdge('1', '3', 8);
		g.AddEdge('1', '5', -4);
		g.AddEdge('2', '4', 1);
		g.AddEdge('2', '5', 7);
		g.AddEdge('3', '2', 4);
		g.AddEdge('4', '1', 2);
		g.AddEdge('4', '3', -5);
		g.AddEdge('5', '4', 6);
		vector<vector<int>> vvDist;
		vector<vector<int>> vvParentPath;
		g.FloydWarshall(vvDist, vvParentPath);
		// 打印任意两点之间的最短路径
		for (size_t i = 0; i < strlen(str); ++i)
		{
			g.PrintShortestPath(str[i], vvDist[i], vvParentPath[i]);
			cout << endl;
		}
	}

在这里插入图片描述
我们也可以把之前小潮的图拿出来测测:
在这里插入图片描述

在这里插入图片描述在这里插入图片描述

三种最短路径算法比较

在图论中,寻找最短路径是常见的问题,有多种算法可以解决这个问题,包括Dijkstra算法、Bellman-Ford算法和Floyd-Warshall算法。下面是对这三种算法的比较:

1. Dijkstra算法

适用场景:适用于没有负权边的加权图,无论是有向还是无向图。

优点

  • 时间复杂度较低,使用优先队列优化后的时间复杂度为O((V+E)logV)。
  • 算法简单,易于理解和实现。

缺点

  • 不能处理含有负权边的图。

2. Bellman-Ford算法

适用场景:适用于任何加权图,包括含有负权边的图,但不能有负权回路。

优点

  • 可以检测并报告图中是否存在负权回路。
  • 对于稀疏图,性能优于Floyd-Warshall算法。

缺点

  • 时间复杂度较高,为O(VE),当E较大时效率低。
  • 每次迭代都需要更新所有边,即使某些边的最短路径已经确定。

3. Floyd-Warshall算法

适用场景:适用于任何加权图,包括含有负权边的图,但不能有负权回路。特别适合于求解所有顶点对之间的最短路径问题。

优点

  • 可以一次计算出所有顶点对的最短路径。
  • 算法简洁,易于理解。

缺点

  • 时间复杂度高,为O(V^3),对于大规模图的计算效率低下。
  • 需要额外的空间来存储中间结果,空间复杂度为O(V^2)。

总结

  • 如果只需要求解单源最短路径问题,且图中没有负权边Dijkstra算法是首选
  • 如果图中可能含有负权边,但没有负权回路,Bellman-Ford算法更为适用
  • 当需要求解所有顶点对之间的最短路径时,Floyd-Warshall算法是最直接的选择,尽管它的时间和空间复杂度较高

选择哪种算法取决于具体的问题背景和图的特性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/794113.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv10改进 | Conv篇 | RCS-OSA替换C2f实现暴力涨点(减少通道的空间对象注意力机制)

一、本文介绍 本文给大家带来的改进机制是RCS-YOLO提出的RCS-OSA模块&#xff0c;其全称是"Reduced Channel Spatial Object Attention"&#xff0c;意即"减少通道的空间对象注意力"。这个模块的主要功能是通过减少特征图的通道数量&#xff0c;同时关注空…

MySQL实战45讲学习笔记(持续更新ing……)

文章目录 一、基础架构&#xff1a;一条SQL查询语句是如何执行的&#xff1f;概览连接器查询缓存分析器优化器执行器 二、日志系统&#xff1a;一条SQL更新语句是如何执行的&#xff1f;redo logbinlog两阶段提交 一、基础架构&#xff1a;一条SQL查询语句是如何执行的&#xf…

动态规划之数字三角形模型+最长上升子序列模型

首先&#xff0c;我们从集合角度重新看待DP&#xff1a; 直接看题&#xff1a;https://www.acwing.com/problem/content/1029/ 就是取纸条的原题&#xff0c;我们令f[i1,j1,i2,j2]表示从(1,1),(1,1)分别走到(i1,j1),(i2,j2)的路径的max i1j1i2j2&#xff0c;于是我们可以把状…

ArrayList----源码分析

源码中的简介&#xff1a; List接口的可调整数组实现。实现所有可选列表操作&#xff0c;并允许所有元素&#xff0c;包括null。除了实现List接口之外&#xff0c;这个类还提供了一些方法来操作内部用于存储列表的数组的大小。(这个类大致相当于Vector&#xff0c;只是它是不同…

广电日志分析系统

需求 广电集团中有若干个系统都产生日志信息&#xff0c;目前大约分布与70到80台服务器中&#xff0c;分别是windows与Linux操作系统。需要将服务器上产生的日志文件利用我们的技术进行解析 设计 每个日志工作站负责30-50个服务器的日志解析工作。可以根据实际需求进行设置&…

ESP32CAM物联网教学11

ESP32CAM物联网教学11 霍霍webserver 在第八课的时候&#xff0c;小智把乐鑫公司提供的官方示例程序CameraWebServer改成了明码&#xff0c;这样说明这个官方程序也是可以更改的嘛。这个官方程序有四个文件&#xff0c;一共3500行代码&#xff0c;看着都头晕&#xff0c;小智决…

基于Python+Flask+MySQL的新冠疫情可视化系统

基于PythonFlaskMySQL的新冠疫情可视化系统 FlaskMySQL 基于PythonFlaskMySQL的新冠疫情可视化系统 项目主要依赖前端&#xff1a;layui&#xff0c;Echart&#xff0c;后端主要是Flask&#xff0c;系统的主要支持登录注册&#xff0c;Ecahrt构建可视化图&#xff0c;可更换主…

Oracle序列迁移重建

原因&#xff1a;oracle数据导入后序列不一致 解决办法&#xff1a;从原库中导出一份最新的序列号&#xff0c;在目标库中导入 1.删除目标库该用户下的所有索引 select DROP SEQUENCE ||sequence_name || ; from dba_sequences where sequence_owner xxxxx;2.查询出所有序列…

edge 学习工具包 math solver

简介 推荐微软推出的学习工具中的两项工具&#xff1a;数学求解器和 pdf 阅读器。 打开 edge 学习工具包的方法 &#xff1a;右上角三点-更多工具-学习工具包。 math solver 除了基础的计算求解外&#xff0c;还用图标展示公式&#xff0c;清晰直观。 地址&#xff1a;求解…

《C语言程序设计 第4版》笔记和代码 第十一章 指针和数组

第十一章 指针和数组 11.1 指针和一维数组间的关系 1 由于数组名代表数组元素的连续存储空间的首地址&#xff0c;因此&#xff0c;数组元素既可以用下标法也可以用指针来引用。 例11.1见文末 2 p1与p在本质上是两个不同的操作&#xff0c;前者不改变当前指针的指向&#xf…

240711_昇思学习打卡-Day23-LSTM+CRF序列标注(2)

240711_昇思学习打卡-Day23-LSTMCRF序列标注&#xff08;2&#xff09; 今天记录LSTMCRF序列标注的第二部分。仅作简单记录 Score计算 首先计算正确标签序列所对应的得分&#xff0c;这里需要注意&#xff0c;除了转移概率矩阵&#x1d40f;外&#xff0c;还需要维护两个大小…

k8s NetworkPolicy

Namespace 隔离 默认情况下&#xff0c;所有 Pod 之间是全通的。每个 Namespace 可以配置独立的网络策略&#xff0c;来 隔离 Pod 之间的流量。 v1.7 版本通过创建匹配所有 Pod 的 Network Policy 来作为默认的网络策略 默认拒绝所有 Pod 之间 Ingress 通信 apiVersion: …

零基础STM32单片机编程入门(九)IIC总线详解及EEPROM实战含源码视频

文章目录 一.概要二.IIC总线基本概念1.总体特征2.通讯流程 三.EEPROM介绍1.M24C08基本介绍2.向M24C08写一个字节时序图3.从M24C08读一个字节时序图 四.GPIO模拟IIC驱动M24C08读写五.CubeMX工程源代码下载六.讲解视频链接地址七.小结 一.概要 IIC(Inter&#xff0d;Integrated …

如何监控 PostgreSQL 中表空间的使用情况并进行合理的管理?

文章目录 如何监控 PostgreSQL 中表空间的使用情况并进行合理的管理 一、引言 在 PostgreSQL 数据库中&#xff0c;表空间&#xff08;Tablespace&#xff09;是用于管理数据库对象存储位置的逻辑存储区域。有效地监控和管理表空间的使用情况对于确保数据库的性能、优化存储资…

第11章 规划过程组(三)(11.11规划成本管理)

第11章 规划过程组&#xff08;三&#xff09;11.11规划成本管理&#xff0c;在第三版教材第403~404页&#xff1b; 文字图片音频方式 第一个知识点&#xff1a;成本管理概述 1、成本的类型&#xff08;重要知识点&#xff09; 直接成本 如项目团队差旅费、工资、项目使用的…

scrapy写爬虫

Scrapy是一个用于爬取网站数据并提取结构化信息的Python框架 一、Scrapy介绍 1.引擎&#xff08;Engine&#xff09; – Scrapy的引擎是控制数据流和触发事件的核心。它管理着Spider发送的请求和接收的响应&#xff0c;以及处理Spider生成的Item。引擎是Scrapy运行的驱动力。…

Qt学生管理系统(付源码)

Qt学生管理系统 一、前言1.1 项目介绍1.2 项目目标 2、需求说明2.1 功能性说明2.2 非功能性说明 三、UX设计3.1 登录界面3.2 学生数据展示3.3 信息插入和更新 三、架构说明3.1 客户端结构如下3.2 数据流程图3.2.1 数据管理3.2.2 管理员登录 四、 设计说明3.1 数据库设计3.2 结构…

unsupported_country_region_territory

最近调用chatgpt接口出现&#xff1a;unsupported_country_region_territory&#xff0c;Country, region, or territory not supported 翻译过来的大致意思就是

合宙 Air780E模块 AT 指令 MQTT连接

固件说明 重启模块 //tx ATRESET//rx ATRESETOK ^boot.romv!\n RDY^MODE: 17,17E_UTRAN ServiceCGEV: ME PDN ACT 1NITZ: 2024/07/10,08:33:440,0查询模块版本信息 //tx ATCGMR//rx ATCGMRCGMR: "AirM2M_780E_V1161_LTE_AT"OK基本流程 4G模块支持MQTT和MQTT SSl协…

某企业数据治理总体解决方案(45页PPT)

引言&#xff1a;集团企业数据治理总体解决方案旨在构建一个高效、安全、合规且灵活的数据管理体系&#xff0c;以支持企业决策优化、业务创新、风险管理和运营效率提升。该方案通过整合数据资源、规范数据流程、强化数据质量和促进数据共享&#xff0c;实现数据资产的最大化价…