12.21~12.24最短路,dij,堆优化dij,spfa

有条件的最短路径一定长于无条件的最短路径

朴素dij

dij的思路就是先入起点,然后从起点开始向四周遍历,每次确定一个实际最短的,,这里注意,正是因为没有负权,所以越早遇到的最短,就一定是最短,不然就有可能后续还有负权会使到这个点的代价更小;

每次迭代确定一个最短的,可优化的就是中间找还没访问过的最短的

 

第 一个for循环仅表示迭代次数,每层迭代下,嵌套两个并列循环,第一个为找到符合要求的点,第二个是依据符合要求的点进行松弛处理操作

for(int i=0; i<n; i++)
	{
		int t = -1;
		for(int j=1; j<=n; j++)   // 在没有确定最短路中的所有点找出距离最短的那个点 t 
		   if(!st[j] && (t == -1 || dist[t] > dist[j]))
		    t=j;                  
		    
		st[t]=true; // 代表 t 这个点已经确定最短路了
		
		for(int j=1; j<=n; j++) // 用 t 更新其他点的最短距离 
		 dist[j] = min(dist[j],dist[t]+g[t][j]);
	 } 

堆优化dij

就是说依据符合要求点进行松弛,如果能成功松弛,就意味着dis缩小了一次,就加入到堆里

在堆里时,判断是否满足条件,就是看该点是否已经被确定,如果该点已经被确定,那么说明在取堆头时,取这个堆头之前就已经有更短的dis到了这个点,那么此时的路径长度就一定不是最短的,所以就不再在此基础上进行松弛;如果没有收集过,就说明是第一次遇到,那么可以据此进行松弛操作;然后在堆里排列的时候,就是严格按照dis的大小排,而不是入队的时间先后顺序

ACD

A注意如果一个节点能多次入队,就说明一直能有路径可以松弛,就是说可以不断更新这个点的最短路径;就是说,入队条件只有能松弛时才会入队,而如果能松弛,就意味着最短路径被更新了,如果某节点能不断入队,说明最短路径在不断的更新

即只要点还没出队,那么它的最小路径就还没确定;而如果一个点的最小路径确定了,那么后续的点也都不可能在对这个点进行松弛操作了,这个点也不会再被更新,重新入队了,因为后续点要进行松弛操作,都是建立在堆的后续基础上,而后续基础都已经比此时的访问代价大了,即

dis[i]<dis[u]<dis[u]+g[u][i]

#include<iostream>
#include<queue>
#include<set>
#include<vector>
using namespace std;
//要做改进就是用布尔vis去记录访问情况
//这个用vis的主要目的不是不让其去更新了,而是为了防止它继续更新,
//由于是基于dis的改良,所以优先队列里记录的就是到各个点的代价,但还需要记录目的地,因为只是记录代价是少信息的
//在dis数组里,下标就代表着目的地
const int maxn = 1e4;
const int maxm = 1e4;
struct edge {
	int v, w, next;
}e[maxm];
int n, m, cnt = 0;
int h[maxn];
void add(int u, int v, int w) {
	e[++cnt].v = v;
	e[cnt].w = w;
	e[cnt].next = h[u];
	h[u] = cnt;
}
typedef pair<int, int> pii;//由于数对的默认排序规则为先比第一个再比第二个,所以就应该定义第一个为距离dis,第二个为目的地编号
int dis[maxn];
int main() {
	dis[1] = 0;
	priority_queue<pii, vector<pii>, greater<pii>>heap;//优先队列的顺序与sort不同,取了个反
	heap.push({ 0,1 });//这个优先队列实际上是把找点与松弛揉到一块了
	while (!heap.empty()) {
		pii t = heap().top;
		heap.pop();
		int u = t.second, d = t.first;//获取数对的第一个第二个信息,不需要(),因为本身就不是函数
		if (st[u])continue;//已经访问过了,已经访问过了就意味着在这个点的基础上已经对后续的点做了松弛操作,那么此时如果再做是完全没意义的
		st[u] = 1;
		for (int i = h[u]; i; i = e[i].next) {
			int v = e[i].v;
			if (dis[v] > dis[u] + e[i].w) {
				dis[v] = dis[u] + e[i].w;
				heap.push({ dis[v],v });
			}
		}
	}
	return 0;
}

 这个dis是从起点到终点的距离,如果某个终点已经确定过了,那么后续如果在确定某个终点后,再次对其可以到达的点做松弛操作,如果可以到达相同的点,其代价一定比现在要大,因为后续的代价是建立在要达到那个代价更大的点的基础上的

这里dis的更新,与访问数组的置1是分离的,数组的置1,代表着这个点已经进行了松弛操作,而不仅意味着是被确定了;但是如果要进行松弛操作,也的是建立在确定的最小dis基础上;而后续再访问到同样的点,其所确定的dis一定比现在大

不能确定负权,是因为比如这个4,假设1到3代价很大,到4的负权也很大,从1到2再到4都是正权,那么会先通过1到2到4,如果4到后续的点代价比到3的代价小,就会在1到2到4的基础上松弛掉后续的所有点,但实际上这些松弛操作都是建立在错误的最小dis基础上的,但如果没有负权的话就不会有这一情况

数对pair的排序规则,优先队列 

数对的优先队列的排序规则是根据数对中的第一个数从大到小排序,如果第一个数相同,则根据第二个数从小到大排序。 

或许基于这一特性可以用来字典序? 

即排序的时候编号都是按照从小到大的字典序了

本来只是希望多一个保留目的地的信息,用了pair之后,不仅保留了目的地的信息,还使其信息按照字典序排序

#include<iostream>
#include<queue>
#include<set>
#include<vector>
using namespace std;
//要做改进就是用布尔vis去记录访问情况
//这个用vis的主要目的不是不让其去更新了,而是为了防止它继续更新,
//由于是基于dis的改良,所以优先队列里记录的就是到各个点的代价,但还需要记录目的地,因为只是记录代价是少信息的
//在dis数组里,下标就代表着目的地
const int maxn = 1e5 + 2;
const int maxm = 2e5 + 3;
struct edge {
	int v, w, next;
}e[maxm];
int n, m, cnt = 0;
int h[maxn];
void add(int u, int v, int w) {
	e[++cnt].v = v;
	e[cnt].w = w;
	e[cnt].next = h[u];
	h[u] = cnt;
}
int dis[maxn];
int s;
const int inf = 1e9;
bool vis[maxn];
typedef pair<int, int> pii;
priority_queue<pii, vector<pii>, greater<pii>>q;
int main() {
	cin >> n >> m >> s;
	for (int i = 1; i <= m; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		add(u, v, w);
	}
	for (int i = 1; i <= n; i++)dis[i] = inf;
	dis[s] = 0;
	q.push({ 0,s });
	while (!q.empty()) {
		int d = q.top().first, tar = q.top().second;
		q.pop();
		if (vis[tar])continue;
		vis[tar] = 1;
		dis[tar] = d;//不应该在这里做修改,因为可能有节点多次入队,
		//但好像也可以,因为前面有是否访问的判断,如果到这里的话,就说是第一次访问到,那就一定是代价最小的
		for (int j = h[tar]; j; j = e[j].next) {
			if (dis[e[j].v] > dis[tar] + e[j].w) {
				q.push({ dis[tar] + e[j].w,e[j].v });
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		cout << dis[i] << " ";
	}
	return 0;
}

注意typedef后要加; 

SPFA

先让初始点入队,然后用队头节点去更新后续可以到达的点,如果更新成功就入队,只有更新成功时才入队,每次操作时,都直接在dis上去操作,

注意是普通队列而不是优先队列,如果有相同的点重复出队,就意味着那个点的dis在不断被更新,在此基础上它也就能不断的去松弛它可以到达的点,进而使后续的点也能被更新

如果有负环的话,会使重复的节点一直重复的入队与出队,即有点的dis在一直被缩小,在此基础上,后续点的dis也可以被缩小,成环的话,那么起点的dis可以继续被缩小,所以就会形成死循环

如果不是负环,正环的话,起始点的dis被更新,后续点也只会被更新一次,就是在新dis基础上做更新,再回来的话,就会有额外成本,松弛不了

如果要判断负环,就多一个cnt数组,记录起点到x的最短路径所经过的边数,如果边数大于等于n了,就说明一定存在负环,因为走完所有点要n-1条边,再加一条就一定会成环,即走过同一节点两次

,这个cnt是在起点处加1做的覆盖,所以即使有负权也不会无限加,而是被这条路径上的cnt所覆盖掉,除非是负环

int dis[maxn];
int cs[maxn];
void spfa(int s) {
	queue<int>q;
	q.push(s);
	dis[s] = 0;
	while (!q.empty()) {
		int cur = q.front();
		q.pop();
		for (int i = h[cur]; i; i = e[i].next) {
			int u = e[i].v;
			if (dis[u] > dis[cur] + e[i].w) {
				q.push(u);
				cs[u] = cs[cur] + 1;
			}
		}
	}
}

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

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

相关文章

智能变电站协议系列-2、SV/SMV协议示例(IEC61850)以及5G专网下的电力方案分析

文章目录 一、前言二、资料准备三、libiec61850的SV运行示例及抓包分析1、单独编译示例程序2、运行示例程序及5G专网场景下部署3、wireshark抓包分析 四、最后 一、前言 之前我们对IEC61850协议有了整体的了解&#xff0c;对一些概念有了一定的认识&#xff0c;并针对GOOSE协议…

JWT、session、token区别和实现

JWT、session、token区别和实现 这里需要用到Redis和JWT。 springboot版本是3.2.1 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency><…

【MySQL】mysql执行查询超过30秒之后报错

出现场景&#xff1a; 用workbench&#xff0c;查本地数据库&#xff0c;执行查询超过30秒之后&#xff0c;会报错断开连接&#xff0c;报错信息&#xff1a;Error Code: 2013. Lost connection to MySQL server during query 解决办法&#xff1a; 修改配置设置&#xff0c…

数据可视化分析大屏,大数据统计UI页面源文件(信息分析平台免费PS资料)

数据可视化可以帮助数据分析者更好地理解数据&#xff0c;发现数据中的规律和趋势。通过图表和图形等可视化工具&#xff0c;数据分析者可以更快速地发现数据中的关系&#xff0c;比如相关性、趋势、异常值等。对于普通用户来说&#xff0c;理解复杂的数据可能会很困难。通过数…

【开源】基于JAVA语言的学校热点新闻推送系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 新闻类型模块2.2 新闻档案模块2.3 新闻留言模块2.4 新闻评论模块2.5 新闻收藏模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 新闻类型表3.2.2 新闻表3.2.3 新闻留言表3.2.4 新闻评论表3.2.5 新闻收藏表 四、系统展…

Anylogic Pro 8.8.x for Mac / for Linux Crack

Digital twins – a step towards a digital enterprise AnyLogic是唯一一个支持创建模拟模型的方法的模拟建模工具&#xff1a;面向过程&#xff08;离散事件&#xff09;、系统动态和代理&#xff0c;以及它们的任何组合。AnyLogic提供的建模语言的独特性、灵活性和强大性使…

上传文件到七牛云的相关代码(可直接用)

首先在七牛云注册&#xff0c;然后选择对象存储&#xff0c;按照以下配置&#xff1a; 我的存储地区是华南-广东&#xff0c;注意这个如果选择不一样&#xff0c;后面的代码调用会有一点区别&#xff0c;访问控制选择公开&#xff0c;不然回显的外链无法访问。 记住这个空间名称…

HarmonyOS构建第一个ArkTS应用(Stage模型)

构建第一个ArkTS应用&#xff08;Stage模型&#xff09; 创建ArkTS工程 若首次打开DevEco Studio&#xff0c;请点击Create Project创建工程。如果已经打开了一个工程&#xff0c;请在菜单栏选择File > New > Create Project来创建一个新工程。 选择Application应用开发…

深入了解 Android 中的应用程序签名

深入了解 Android 中的应用程序签名 一、应用程序签名介绍1.1 应用程序签名1.2 应用程序签名的意义1.3 应用程序签名的流程1.4 应用程序签名的方案1.5 签名的重要性和应用场景 二、AOSP 的应用签名2.1 AOSP的应用签名文件路径2.2 应用程序指定签名文件 三、Android Studio 的应…

10:IIC通信

1&#xff1a;IIC通信 I2C总线&#xff08;Inter IC BUS&#xff09; 是由Philips公司开发的一种通用数据总线&#xff0c;应用广泛&#xff0c;下面是一些指标参数&#xff1a; 两根通信线&#xff1a;SCL&#xff08;Serial Clock&#xff0c;串行时钟线&#xff09;、SDA&a…

物联网协议之COAP简介及Java实践

目录 前言 一、COAP简介 1、关于COAP 2、COAP特点 3、基于COAP的NB-IoT接入流程 二、CoAP协议JAVA实践 1、californium介绍 2、Java集成 3、Maven 资源引入 4、定义Server端 5、Client调用 6、运行测试 总结 前言 今天平安夜&#xff0c;祝大家圣诞快乐&#xff0c…

41 sysfs 文件系统

前言 在 linux 中常见的文件系统 有很多, 如下 基于磁盘的文件系统, ext2, ext3, ext4, xfs, btrfs, jfs, ntfs 内存文件系统, procfs, sysfs, tmpfs, squashfs, debugfs 闪存文件系统, ubifs, jffs2, yaffs 文件系统这一套体系在 linux 有一层 vfs 抽象, 用户程序不用…

前端---html 的介绍

1. 网页效果图 --CSDN 2. html的定义 HTML 的全称为&#xff1a;HyperText Mark-up Language, 指的是超文本标记语言。 标记&#xff1a;就是标签, <标签名称> </标签名称>, 比如: <html></html>、<h1></h1> 等&#xff0c;标签大多数都是…

一篇文章拿捏继承多态练习题

继承多态习题 选择题解释 简答题 选择题 下面哪种面向对象的方法可以让你变得富有( ) A: 继承 B: 封装 C: 多态 D: 抽象 ( )是面向对象程序设计语言中的一种机制。这种机制实现了方法的定义与具体的对象无关&#xff0c; 而对方法的调用则可以关联于具体的对象。 A: 继承 B: 模…

Linux系统编程(六):进程(下)

参考引用 UNIX 环境高级编程 (第3版)嵌入式Linux C应用编程-正点原子 1. 进程与程序 1.1 main() 函数由谁调用&#xff1f; C 语言程序总是从 main 函数开始执行int main(void) int main(int argc, char *argv[]) // 如果需要向应用程序传参&#xff0c;则选择该种写法操作系…

TikTok真题第3天 | 856.括号的分数、2115. 从给定原材料中找到所有可以做出的菜、394.字符串解码

856.括号的分数 题目链接&#xff1a;856.score-of-parentheses 解法&#xff1a; leetcode官方的题解基本是每个字都认得&#xff0c;连起来就看不懂。 使用栈来解决&#xff0c;后进先出&#xff0c;后面加入的左括号&#xff0c;先弹出和右括号去匹配。定义一个记录分数…

部署LNMP动态网站

部署LNMP动态网站 安装LNMP平台相关软件1. 安装软件包2. 启动服务&#xff08;nginx、mariadb、php-fpm&#xff09;3. 修改Nginx配置文件&#xff0c;实现动静分离4. 配置数据库 上线wordpress代码 &#xff08;测试搭建的LNMP环境是否可以使用&#xff09;1. 上线php动态网站…

什么等等? I/O Wait ≠ I/O 瓶颈?

本文地址&#xff1a;什么等等&#xff1f; I/O Wait ≠ I/O 瓶颈&#xff1f; | 深入浅出 eBPF 1. I/O Wait 定义2. 测试验证3. 进一步明确磁盘吞吐和读写频繁进程4. 内核 CPU 统计实现分析5. 总结参考资料 1. I/O Wait 定义 I/O Wait 是针对单个 CPU 的性能指标&#xff0…

Bresenham 算法

1965 年&#xff0c;Bresenham 为数字绘图仪开发了一种绘制直线的算法&#xff0c;该算法同样使用于光栅扫描显示器&#xff0c;被称为 Bresenham 算法。 原理 算法的目标是选择表示直线的最佳光栅位置。Bresenhan 算法在主位移方向上每次递增一个单位。另一个方向的增量为 0…

【java爬虫】基于springboot+jdbcTemplate+sqlite+OkHttp获取个股的详细数据

注&#xff1a;本文所用技术栈为&#xff1a;springbootjdbcTemplatesqliteOkHttp 前面的文章我们获取过沪深300指数的成分股所属行业以及权重数据&#xff0c;本文我们来获取个股的详细数据。 我们的数据源是某狐财经&#xff0c;接口的详细信息在下面的文章中&#xff0c;本…