图论(五)-最短路

news2025/2/23 10:46:33

一、Bellman-Ford算法 

        算法思想:通过 n 次循环,每次循环都遍历每条边(共 m 条边),进而更新节点的距离,每次循环至少可以确定一个点的最短路,循环 n 次,求出 n 个点的最短路

        时间复杂度 : O(mn)  (n为节点个数,m为边总数)

        与前面所述的dijkstra算法不同,Bellman-Ford 算法可以处理含负权边的单源最短路问题,同时可以判断是否存在负权回路。

        算法描述:

        ①初始化:将除起始点 s 以外的 dis 数组设置为 无穷大, dis[ s ] = 0

        ②迭代:遍历图中的每条边,对边的两个顶点分别进行松弛操作,一共遍历 n 次 m条边,直到没有节点能够松弛

        ③判断负环:Bellman-Ford算法迭代后,再迭代一次,若最短路距离发生改变,则存在负环。

        核心代码:

for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
    int u=edge[i].u;
    int v=edge[i].v;
    int w=edge[i].w;
  	 if(dist[u]+v<dist[v])
  	   dist[v]=dist[u]+w; //松弛
}

应用

        Bellman-Ford算法,第 i 次循环 m 条边时,可以确定走 i 条路到达的点的最短距离。 当图为一条直线时,需要 n-1 次循环即可确定最短路。

求有边数限制的最短路

        通过上述 Bellman-Ford算法思路,若求 k 条边数限制的最短路,仅需要循环 k 次 m条边,以下图举例说明。

        

    k = 1 时,通过上述代码,遍历一次即可算出 节点2 3 的最短路,但是这是错误的。当边的顺序为 (2,3,3)  (1,2,2) 时,遍历一次仅可以求出 节点2 的最短路,说明上述仅遍历一次得出的 节点3 不一定是最短路。

    考虑原问题,若需要求 k 条边限制的最短路

     通过第一种情况边的顺序可以得出 dis[ 3 ] 为 5 ,可是显然仅走1条边时到达不了节点3

     而通过第二种情况边的顺序又可以得出正确结果。但是当节点数明显增多时,边的顺序无法自行更改,应该如何处理?

        进行备份,保存其上一[2] 应为第0条边时的值(正无穷),同时将备份数组不断更新。层的状态,对该状态进行松弛操作(即当考虑第k条边时,对其考虑第 k-1 条边的状态进行松弛操作),在上述图例中,当对 节点3 进行松弛操作的 dis

        此外,当存在负权边时,仍然会更新,可是更新后的大小为 正无穷+负权值,在最后判断是否到达该节点时仅需判断 

if ( dist [n] > 0x3f3f3f3f/2 ) return -1;

核心代码:

memset(dis,0x3f,sizeof(dis));
dist[1]=0;
for(int i=1;i<=k;i++) 
{
    for(int j=1;j<=n;j++) bf[i]=dis[i];
	for(int j=1;j<=m;j++)   // 枚举所有边 
	{
		 int a=edge[j].a,b=edge[j].b,w=edge[j].w;	
		 dis[b]=min(dis[b],bf[a]+w); // 用备份更新 
	}
}
if(dist[n]>0x3f3f3f3f/2) return -1;
return dist[n];

二、SPFA算法

        SPFA算法是在上述 Bellman-Ford 基础上优化得来的,Bellman-Ford中,当某个点未被更新过,仍会用该点去更新其他节点,这是无意义的,使得效率降低,SPFA中将更新后的节点再去更新其他节点即可。

void spfa()
{// 将更新的节点加入队列中,队列中的元素即为已更新的节点
	memset(dis,0x3f,sizeof(dis));
	dist[1]=0;
	queue<int>q;
	q.push(1); //入队 
	st[1]=1; // 队列中含有该节点
	while(q.size()) // 队列不空
	{
	   int u=q.front(); 
	   q.pop();
	   st[u]=0; // 出队
	   for(int i=head[u];i!=-1;i=edge[i].next)
	   {
	   	 int v=edge[i].v;
	   	 int w=edge[i].w; 
         if(dis[v]>dis[u]+w)
	   	 {
	   	    dis[v]=dis[u]+w;
			if(!st[v])  //如果不在队列中,入队
			{
				q.push(v); 
				st[v]=1;		    } 	    	
		 }
	   }	
	} 
}

SPFA应用:判断负环

        负环:当图中存在一个环,使得绕环遍历一圈的结果为负数,这样绕该环一直遍历,最短距离不断减小,不存在最短路

SPFA判断负环:用一个 cnt [x] 数组存储 起点到 x 点的最短路径经过的边数,因为SPFA为最短路算法,经过的边数一定<n ,若 cnt 数组的某个值 >=n , 则说明存在负环。

        此外,通过链式前向星构建的图不一定是连通的,可能存在自环的情况(负自环),因此需要首先将所有节点入队。

bool spfa()
{// 将更新的节点加入队列中,队列中的元素即为已更新的节点
	memset(dis,0x3f,sizeof(dis));
	dist[1]=0;
	queue<int>q;
    for(int i=1;i<=n;i++)
    {
	    q.push(i); //入队 
	    st[i]=1; // 队列中含有该节点
	}
    while(q.size()) // 队列不空
	{
	   int u=q.front(); 
	   q.pop();
	   st[u]=0; // 出队
	   for(int i=head[u];i!=-1;i=edge[i].next)
	   {
	   	 int v=edge[i].v;
	   	 int w=edge[i].w; 
         cnt[v]=cnt[u]+1;
         if(cnt[v]>=n) return true; // 经过边数>=n,存在负环
         if(dis[v]>dis[u]+w)
	   	 {
	   	    dis[v]=dis[u]+w;
			if(!st[v])  //如果不在队列中,入队
			{
				q.push(v); 
				st[v]=1;
		    } 	    	
		 }
	   }	
	} 
}

三、Floyd 算法

        Floyd 算法可以实现多源最短路,思想基于动态规划,从 节点i 到 节点j 的路径有两种

        1.从 节点i 直接到 节点j  dis[i][j]=dis[i][j]

        2. 节点i 经过某些节点到达 节点k 再经过某些节点到达 节点j   dis[i][j]=dis[i][k]+dis[k][j] 

        通过上面两种方式进行更新

        时间复杂度为 O(n^{3} )

void floyd()
{
 for(int k=1;k<=n;k++)
   for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
      d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}

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

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

相关文章

git:Unable to negotiate问题解决

场景说明&#xff1a; 安装了Gitblit(自架的代码仓库服务)发现部分电脑无法推代码&#xff0c;报错误如下&#xff1a; Unable to negotiate with **** port 22: no matching host key type found. Their offer: ssh-rsa 并排队了账户权限问题。 解决方案&#xff1a; 1.打开问…

HttpClient cookie爬虫记录

记录一次java语言使用httpclient爬取网站接口数据的经历 需要用到的依赖&#xff1a; httpclient和httpcore是封装了http请求的工具类 jsoup可以将返回的网页html找到你需要的xml节点&#xff0c;很方便 <dependency><groupId>org.apache.httpcomponents</gr…

Spring系列-01-IOC的依赖查找和依赖注入

IOC基础 IOC发展 初始场景, 不使用IOC如何实现 假定现在有一下需求, 开始使用的数据源是MySQL, 后续数据源变动为Oracle, 那么我们的代码就需要改动 每次切数据源都需要改动, 那么进行优化 静态工厂解决强依赖 在01版本基础上, 使用静态工厂对多个数据源进行了封装, 要哪…

Unity UGUI系统概念分析

文章目录 前言一、UGUI运行原理二、UGUI组件分析1、Canvas组件2、Canvas Scaler3、Graphic Raycaster组件4、EventTrigger组件5、Image 和 RawImage组件5、Mask 和 RectMask2D组件6、Button、Sider、DropDown等组件 三、UGUI源码分析三、UGUI优化四、UI框架设计五、UI适配总结 …

三十一、openlayers官网示例Draw Features解析——在地图上自定义绘制点、线、多边形、圆形并获取图形数据

官网demo地址&#xff1a; Draw Features 先初始化地图&#xff0c;准备一个空的矢量图层&#xff0c;用于显示绘制的图形。 initLayers() {const raster new TileLayer({source: new XYZ({url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/…

快团团帮卖团长怎么对供货大团长进行评分?

都说帮卖“躺赚”&#xff1f; 一旦遇团不淑&#xff0c;惨遭不靠谱团长挖坑&#xff0c;售后拖延、发货慢、产品瑕疵…… 加上顾客夺命连环催&#xff0c;双面夹击&#xff0c;夹缝生存。供货团长靠不靠谱太重要了&#xff01; 快团团供货团长评分系统上线&#xff01; 帮卖团…

深入理解MySQL索引下推优化

在MySQL中&#xff0c;索引的使用对于查询性能至关重要。然而&#xff0c;即使有合适的索引&#xff0c;有时查询性能仍然不尽如人意。索引下推&#xff08;Index Condition Pushdown&#xff0c;ICP&#xff09;是一项能够进一步优化查询性能的技术。本文将详细讲解索引下推的…

Postman入门 - 环境变量和全局变量

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、发送请求 二、设置并引用环境变量 比如&#xff1a;我建的这个生产环境 使用环境有两个方式&…

大学数学常用的搜题软件?分享四个搜题直接出答案的软件 #微信#媒体#职场发展

以下软件拥有强大的搜索功能&#xff0c;能够快速找到与题目相关的资料和答案&#xff0c;让大学生们更容易理解和掌握知识点。 1.The Sky The Sky 是一个让人惊艳的天文知识学习软件&#xff0c;也是一个唯美好看的天文科普软件。 它的功能全面丰富&#xff0c;支持识别查看…

常见排序算法之插入排序

目录 一、直接插入排序 1.1 什么是插入排序 1.2 代码思路 1.3 C语言源码 二、希尔排序 2.0 插入排序的弊端 2.1 什么是希尔排序&#xff1f; 2.2 排序思路 2.3 C语言源码 一、直接插入排序 1.1 什么是插入排序 插入排序是一种简单直观的排序算法&#xff0c;它通过构…

003 仿muduo实现高性能服务器组件_前置知识

​&#x1f308;个人主页&#xff1a;Fan_558 &#x1f525; 系列专栏&#xff1a;仿muduo &#x1f339;关注我&#x1f4aa;&#x1f3fb;带你学更多知识 文章目录 前言时间轮timewheel设计正则表达式介绍&#xff08;了解知道怎么使用&#xff09;通用型any容器的实现 小结 …

蓝牙模块选型之蓝牙功能

蓝牙模块&#xff0c;是一种集成蓝牙功能的PCBA板&#xff0c;用于短距离无线通讯&#xff0c;蓝牙模块将芯片和外围硬件电路集成到一个PCB上&#xff0c;开发出所需的内置程序实现蓝牙功能的设备。可以通过相关接口和MCU控制设备进行数据传输、可实现蓝牙标准通信和组网。 目前…

海外仓系统要多少钱?最贵的未必是最好的,性价比高的才是

海外仓系统可以说已经是现在海外仓管理不可或缺的重要工具&#xff0c;然而&#xff0c;很多海外仓企业在选择海外仓系统时最头疼的问题就是不知道到底多少钱才合适。 确实&#xff0c;现在的海外仓系统市场价格体系非常多&#xff0c;几万几十万各种定价都有&#xff0c;让人…

揭秘编程逻辑:布瑞克(break)与坎特牛(continue)的较量

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、布瑞克与坎特牛&#xff1a;逻辑差异的探索 二、代码案例分析&#xff1a;布瑞克与坎特…

远程抄表及预付费管理系统:智能管理的新篇章

1.系统简述 远程抄表及预付费管理系统是现代能源管理方面的一项重要自主创新&#xff0c;它将传统手动式抄水表方式转变为自动化技术、智能化管理模式&#xff0c;大大提高了高效率并减少了经营成本。该系统搭载了前沿的通讯技术、数据分析技术和财务管理系统核心理念&#xf…

UVa1466/LA4849 String Phone

UVa1466/LA4849 String Phone 题目链接题意分析AC 代码 题目链接 本题是2010年icpc亚洲区域赛大田赛区的G题 题意 平面网格上有n&#xff08;n≤3000&#xff09;个单元格&#xff0c;各代表一个重要的建筑物。为了保证建筑物的安全&#xff0c;警察署给每个建筑物派了一名警察…

使用 Flask 和 Vue.js 构建 Web 应用

文章目录 入门1. 设置 Flask 后端2. 设置 Vue.js 前端 将 Flask 与 Vue.js 集成1. 配置 Flask 来提供 Vue.js 文件2. 构建 Vue.js 组件3. 运行应用程序 结论 在现代 Web 开发中&#xff0c;创建动态和响应式的应用通常涉及将后端框架如 Flask 与前端库如 Vue.js 结合起来。这种…

深度合作!博睿数据联合中国信通院开展公网服务质量评估工作!

近日&#xff0c;中国信息通信研究院&#xff08;简称“中国信通院”&#xff09;算网质量保障工作全面启动&#xff0c;博睿数据&#xff08;bonree.com&#xff0c;股票代码688229&#xff09;作为信通院算网质量测试独家技术支持单位&#xff0c;提供公网服务质量测评整体解…

新手做抖店该怎么选品?怎么选爆款?选爆品牢记这五大方法

大家好&#xff0c;我是电商花花。 不论之前还是现在&#xff0c;我们做电商想要出单&#xff0c;赚钱&#xff0c;选品对于我们店铺来说都是至关重要的&#xff0c;我们能不能在抖店上赚钱&#xff0c;就看我们的选品&#xff0c;看我们商品选的怎么样了。 如果品选的不错&a…