多源最短路径算法:Floyd-Warshall算法分析

在这里插入图片描述

文章目录

    • 图的邻接矩阵
  • 一.Floyd-Warshall算法思想(基于动态规划)
  • 二.Floyd-Warshall算法接口
  • 笔记附录:单源最短路径--Bellman-Ford算法
    • 1.Bellman-Ford算法接口核心部分
    • 2.Bellman-Ford算法接口

图的邻接矩阵

namespace Graph_Structure
{//Vertex是代表顶点的数据类型,Weight是边的权值的数据类型,MAX_W是权值的上限值(表示不相两)//Direction表示图是否为有向图template<class Vertex, class Weight = int, Weight MAX_W = INT_MAX, bool Direction = false>class Graph{typedef Graph<Vertex, Weight, MAX_W, Direction> Self;public://使用编译器的默认构造函数Graph() = default;//给定一个存放顶点的数组用来初始化图Graph(const Vertex* a, size_t n){_vertexs.reserve(n);_indexMap.rehash(n);_matrix.resize(n, std::vector<Weight>(n, MAX_W));for (size_t i = 0; i < n; ++i){_vertexs.push_back(a[i]);//建立顶点和数组下标的映射(目的是为了邻接矩阵的边存储)_indexMap[a[i]] = i;}}//获取顶点在邻接矩阵中对应的下标size_t GetVertexIndex(const Vertex& vertex){if (_indexMap.find(vertex) == _indexMap.end()){throw "invalued_para";return -1;}return _indexMap[vertex];}void _AddEdge(size_t srci, size_t dsti, const Weight& w){//判断是有向图还是无向图if (Direction == false){_matrix[dsti][srci] = w;}_matrix[srci][dsti] = w;}//给定起点和终点,在邻接矩阵中添加一条边void AddEdge(const Vertex& src, const Vertex& dst, const Weight& w){if (_indexMap.find(src) == _indexMap.end() || _indexMap.find(dst) == _indexMap.end()){throw "invalued_para";}size_t srci_index = GetVertexIndex(src);size_t dst_index = GetVertexIndex(dst);_AddEdge(srci_index, dst_index, w);}//将图的邻接矩阵打印出来void Print(){for (auto e : _vertexs){std::cout << e << '[' << _indexMap[e] << ']' << std::endl;}std::cout << "     ";for (int i = 0; i < _vertexs.size(); ++i){std::cout << i << "    ";}std::cout << std::endl;int i = 0;for (auto arry : _matrix){std::cout << i++ << ' ';for (auto e : arry){if (e == MAX_W){printf("%4c ", '*');}else{printf("%4d ", e);}}std::cout << std::endl;}}//图的广度优先遍历void BFS(const Vertex& src){size_t begin = GetVertexIndex(src);std::queue<int> QNode;std::vector<bool> Label(_vertexs.size(), false);QNode.push(begin);Label[begin] = true;size_t Level = 0;while (!QNode.empty()){size_t LevelSize = QNode.size();for (size_t i = 0; i < LevelSize; ++i){size_t front = QNode.front();QNode.pop();std::cout << _vertexs[front] << '[' << front << ']' << std::endl;for (int j = 0; j < _vertexs.size(); ++j){if (Label[j] == false && _matrix[front][j] != MAX_W){QNode.push(j);Label[j] = true;}}}}}//图的深度优先遍历void DFS(const Vertex& src){std::vector<bool> visited(_vertexs.size(), false);_DFS(GetVertexIndex(src), visited);}private:void _DFS(size_t srci, std::vector<bool>& visited){visited[srci] = true;std::cout << _vertexs[srci] << '[' << srci << ']' << std::endl;for (int i = 0; i < _vertexs.size(); ++i){if (_matrix[srci][i] != MAX_W && visited[i] == false){_DFS(i, visited);}}}private:std::vector<Vertex> _vertexs;						// 顶点集合std::unordered_map<Vertex, size_t> _indexMap;		// 顶点映射下标std::vector<std::vector<Weight>> _matrix;			// 邻接矩阵};
}

在有向赋权图中(可以存在带负权值的路径,但不能存在总权值为负数的环路),Floyd-Warshall算法可以求出任意两个顶点间的最短路径

一.Floyd-Warshall算法思想(基于动态规划)

  • 假设图中有N个顶点,顶点按照0~N-1进行编号

  • 算法中使用二维数组Dist来记录点与点之间的最短路径长度,Dist[i][j]表示第i个顶点到第j个顶点的最短路径长度,Dist数组的初始状态图的邻接矩阵的拷贝

  • 任意两个顶点ij之间的最短路径上可能存在0 ~ N-2个顶点:在这里插入图片描述

  • 假设顶点i到顶点j的最短路径上编号最大的顶点k顶点,ik之间的路径为p1,kj之间的路径为p2(不难证明,p1同时也是顶点i到顶点k的最短路径,p2同时也是顶点k到顶点j的最短路径)

  • 从而有状态转移方程: Dist[i][j] = Dist[i][k] + Dist[k][j]在这里插入图片描述

  • 最短路径p1p2也可以按照相同的方式划分出子路径.重复路径划分,直到将路径划分成不能再被分割的各个最小状态,从各个最小状态开始进行状态转移就可以得到顶点i到顶点j的最短路径.

  • 状态转移任意两点的最短路径的过程可以通过如下循环完成:

			//动态规划求最优解for (int k = 0; k < _vertexs.size(); ++k){for (int i = 0; i < _vertexs.size(); ++i){for (int j = 0; j < _vertexs.size(); ++j){if (Dist[i][k] != MAX_W && Dist[k][j] != MAX_W &&Dist[i][k] + Dist[k][j] < Dist[i][j]){Dist[i][j] = Dist[i][k] + Dist[k][j];}}}}

在这里插入图片描述

  • 其他任意两点的最短路径的确定过程也是类似的

二.Floyd-Warshall算法接口

		//多源最短路径算法(允许带负权路径存在)//Dist数组用于记录顶点间的最短路径的长度//ParentPath数组用于记录最短路径上某个顶点的前驱结点编号void FloydWarShall(std::vector<std::vector<Weight>>& Dist, std::vector<std::vector<int>>& ParentPath){Dist.resize(_vertexs.size(), std::vector<Weight>(_vertexs.size(), MAX_W));ParentPath.resize(_vertexs.size(), std::vector<int>(_vertexs.size(), -1));//根据图的邻接矩阵初始化Dist数组for (int i = 0; i < _matrix.size(); ++i){for (int j = 0; j < _matrix.size(); ++j){if (i == j){Dist[i][j] = 0;}else if(_matrix[i][j] != MAX_W){Dist[i][j] = _matrix[i][j];ParentPath[i][j] = i;}}}//动态规划求各个最短路径for (int k = 0; k < _vertexs.size(); ++k){for (int i = 0; i < _vertexs.size(); ++i){for (int j = 0; j < _vertexs.size(); ++j){if (Dist[i][k] != MAX_W && Dist[k][j] != MAX_W &&Dist[i][k] + Dist[k][j] < Dist[i][j]){Dist[i][j] = Dist[i][k] + Dist[k][j];//i到j最短路径上,j顶点的前驱为k到j最短路径上j的前驱ParentPath[i][j] = ParentPath[k][j];}}}}}

笔记附录:单源最短路径–Bellman-Ford算法

  • Bellman-Ford算法可以在带负权路径的图中求解单源最短路径的问题
  • 一维数组Dist用于记录源点到其他顶点的最短路径的长度:Dist[i]表示源点到i号结点的最短路径长度
  • 一维数组ParentPath数组用于记录最短路径上某个顶点的前驱结点编号:ParentPath[i]表示在最短路径上,第i号结点的前驱结点的编号

1.Bellman-Ford算法接口核心部分

			for (int i = 0; i < _vertexs.size() - 1; ++i){for (int j = 0; j < _vertexs.size(); ++j){for (int k = 0; k < _vertexs.size(); ++k){if (_matrix[j][k] != MAX_W && dist[j] != MAX_W &&_matrix[j][k] + dist[j] < dist[k]){dist[k] = _matrix[j][k] + dist[j];parentPath[k] = j;}}}
  • 可以证明:上面的循环可以遍历任何一条可能存在的最短路径.对于任意一条最短路径,内部的双层循环至少可以记录下最短路径上的一条边,因此最外层循环只要进行N-1次(N为图的顶点数目)就可以遍历完所有的最短路径:在这里插入图片描述
  • Bellman-Ford算法需要检验图中是否存在总权值为负数的环路,存在总权值为负数的环路的图无法求解最短路径问题

2.Bellman-Ford算法接口

		//带负权路径的单源最短路径算法bool BellmanFord(const Vertex& src, std::vector<Weight>& dist, std::vector<int>& parentPath){dist.resize(_vertexs.size(), MAX_W);parentPath.resize(_vertexs.size(), -1);int srci = GetVertexIndex(src);dist[srci] = Weight();bool flag = true;for (int i = 0; i < _vertexs.size() - 1; ++i){for (int j = 0; j < _vertexs.size(); ++j){for (int k = 0; k < _vertexs.size(); ++k){if (_matrix[j][k] != MAX_W && dist[j] != MAX_W &&_matrix[j][k] + dist[j] < dist[k]){//经过j结点,更新源点到k结点的路径长度dist[k] = _matrix[j][k] + dist[j];parentPath[k] = j;flag = false;}}}if (flag){//路径不再发生更新,则说明所有最短路径都已经确定return false;}flag = true;}//检验图中是否存在负权环路//如果存在负权环路,则Dist数组会继续被更新flag = false;for (int j = 0; j < _vertexs.size(); ++j){for (int k = 0; k < _vertexs.size(); ++k){if (_matrix[j][k] != MAX_W && dist[j] != MAX_W &&_matrix[j][k] + dist[j] < dist[k]){dist[k] = _matrix[j][k] + dist[j];flag = true;}}}return flag;}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

three.js(九):内置的路径合成几何体

路径合成几何体 TubeGeometry 管道LatheGeometry 车削ExtrudeGeometry 挤压 TubeGeometry 管道 TubeGeometry(path : Curve, tubularSegments : Integer, radius : Float, radialSegments : Integer, closed : Boolean) path — Curve - 一个由基类Curve继承而来的3D路径。 De…

【CSS】轮播图案例开发 ( 基本设置 | 子绝父相 | 浏览器水平居中 | 圆角设置 | 绝对定位居中设置 )

代码示例 : <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Banner 轮播</title><style>/* 取消浏览器或者其它标签的默认的内外边距 */* {margin: 0;padding: 0;}/* 取消列表样式 主要是…

百万级并发IM即时消息系统(2)

1.用户model type UserBasic struct {gorm.ModelName stringPassWord stringPhone string valid:"matches(^1[3-9]{1}\\d{9}$)"Email string valid:"email"Avatar string //头像Identity stringClientIp s…

nepctf2023 部分web复现

目录 <1> EZJAVA_CHECKIN(shiro550) <2> 独步天下-转生成为镜花水月中的王者(环境变量提权) <3> 独步天下-破除虚妄_探见真实(Venom代理&ping%0a绕过rce&c文件描述符未关闭连接父进程修改文件权限) <4> 独步天下-破除试炼_加冕成王(tp6rceu…

【Go 基础篇】Go语言数组内存分析:深入了解内部机制

在Go语言中&#xff0c;数组是一种基本的数据结构&#xff0c;用于存储一系列相同类型的元素。虽然数组在应用中非常常见&#xff0c;但了解其在内存中的存储方式和分配机制仍然是一个重要的课题。本文将深入探讨Go语言数组的内存分析&#xff0c;揭示数组在内存中的布局和分配…

网络协议三要素

计算机语言作为程序员控制一台计算机工作的协议&#xff0c;具备了协议的三要素。 语法&#xff0c;就是这一段内容要符合一定的规则和格式。例如&#xff0c;括号要成对&#xff0c;结束要使用分号等。语义&#xff0c;就是这一段内容要代表某种意义。例如数字减去数字是有意…

【Hadoop】Hadoop入门概念简介

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,Java基础学习,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的…

ES6 新特性

&#x1f384;欢迎来到边境矢梦的csdn博文&#x1f384; &#x1f384;本文主要梳理前端技术的JavaScript的知识点ES6 新特性文件上传下载&#x1f384; &#x1f308;我是边境矢梦&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以…

关于linux openssl的自签证书认证与nginx配置

自签文档链接 重点注意这块&#xff0c;不能写一样的&#xff0c;要是一样的话登录界面锁会报不安全 域名这块跟最后发布的一致 nginx配置的话 server {listen 443 ssl; //ssl 说明为https 默认端口为443server_name www.skyys.com; //跟openssl设置的域名保持一致s…

传送带下料口堵塞识别检测算法 yolov5

传送带下料口堵塞识别检测算法通过python基于yolov5网络深度学习框架模型&#xff0c;下料口堵塞识别检测算法能够准确判断下料口是否出现堵塞现象&#xff0c;一旦发现下料口堵塞&#xff0c;算法会立即抓拍发出告警信号。Python是一种由Guido van Rossum开发的通用编程语言&a…

Power BI 连接 MySQL 数据库

Power Query 或 Power BI 只提供了对 SQL Server 的直接连接&#xff0c;而不支持其它数据库的直连。所以第一次连接 MySQL 数据库时&#xff0c;就出现下面的错误信。 这就需要我们自己去安装一个连接器组件。https://downloads.mysql.com/archives/c-net/ 错误解决方案 我一…

【Unity】终极移动指南-注解【理解移动到抓钩,再到贪吃蛇的实现】

文章目录 【Unity】终极移动指南-注解&#xff08;从移动、抓钩到贪吃蛇&#xff09;观前提醒链接地址&#xff1a; 内容一、 transform移动操作【1】transform.position变换位置【2】transform.Translate平移【3】transform.position 类似平移的操作【4】定向矢量【5】停在指定…

定位与轨迹-百度鹰眼轨迹开放平台-学习笔记

1. 百度鹰眼轨迹的主要功能接口 百度的鹰眼轨迹平台&#xff0c;根据使用场景不同&#xff0c;提供了web端、安卓端等各种类型的API与SDK&#xff0c;本文章以web端API为例&#xff0c;介绍鹰眼轨迹的使用。 2. API使用前的准备 使用鹰眼轨迹API&#xff0c;需要两把钥匙&…

Java单元测试 JUnit 5 快速上手

一、背景 什么是 JUnit 5&#xff1f;首先就得聊下 Java 单元测试框架 JUnit&#xff0c;它与另一个框架 TestNG 占据了 Java领域里单元测试框架的主要市场&#xff0c;其中 JUnit 有着较长的发展历史和不断演进的丰富功能&#xff0c;备受大多数 Java 开发者的青睐。 而说到…

SpringBoot整合JUnit、MyBatis、SSM

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 SpringBoot整合 一、SpringBoot整合JUnit二、Spri…

Vue脚手架中安装ElementUi

目录 ElementUi简介&#xff1a; ElementUi下载&#xff1a; npm 安装&#xff1a; 引入ElementUi: 测试是否引入成功&#xff1a; Element-ui官网&#xff1a;组件 | Element ElementUi简介&#xff1a; ElementUi&#xff0c;是由国内的饿了么团队开发并开源的一套为开…

砍价活动制作秘籍,打造抢购风潮

砍价活动作为一种吸引用户参与、提高销售量的营销手段&#xff0c;已经成为了电商行业的热门选择。在如今竞争激烈的市场环境下&#xff0c;如何制作出成功的砍价活动&#xff0c;成为了每位电商从业者亟需解决的问题。在本文中&#xff0c;我们将为大家揭秘一种制作成功砍价活…

基于Thinkphp6框架全新UI的AI网址导航系统源码

2023全新UI的AI网址导航系统源码&#xff0c;基于thinkphp6框架开发的 AI 网址导航是一个非常实用的工具&#xff0c;它能够帮助用户方便地浏览和管理自己喜欢的网站。 相比于其他的 AI 网址导航&#xff0c;这个项目使用了更加友好和易用的 ThinkPHP 框架进行搭建&#xff0c;…

[管理与领导-60]:IT基层管理者 - 扩展技能 - 3 - 通过面试招到合适的人选

目录 前言&#xff1a; 一、招聘 1.1 什么是招聘 1.2 招聘 VS 招募 1.3 甄选 1.4 招聘中的重要原则 1.5 招聘的本质 1.6 人才匹配的维度 1.7 人员招聘中的误区 二、面试 2.1 何为面试 2.2 为什么面试 2.3 面试的注意事项 2.4 面试的误区 2.5 如何进行面试 前言…

ffmpeg把RTSP流分段录制成MP4,如果能把ffmpeg.exe改成ffmpeg.dll用,那音视频开发的难度直接就降一个维度啊

比如&#xff0c;原来我们要用ffmpeg录一段RTSP视频流转成MP4&#xff0c;我们有两种方案&#xff1a; 方案一&#xff1a;可以使用以下命令将rtsp流分段存储为mp4文件 ffmpeg -i rtsp://example.com/stream -vcodec copy -acodec aac -f segment -segment_time 3600 -reset_t…