单元最短路模板 dijkstra以及SPFA的FAQ

单源最短路

首先先看两道题目:
Luogu P3371 【模板】单源最短路径(弱化版)
Luogu P4779 【模板】单源最短路径(标准版)
两道题目都是求最小单元最短路。
使用Dijkstra两道题目均可以通过,但是如果使用SPFA则只能通过Luogu P3371

SPFA

依据Bellman-Ford算法,其在计算过程中,保证BFS队列中不会出现两个相同的元素,其复杂度为 O ( q m ) O(qm) O(qm),其中 q q q为每个节点的平均入队次数,已经有人证明最坏情况下复杂度为 O ( n m ) O(nm) O(nm)Bellman-Ford算法复杂度相同,但是在随机数据情况下速度快于Bellman-Ford,与Bellman-Ford都可以处理边权有负数的情况。

Dijkstra

不能处理边权为负数的情况复杂度 O ( m l o g n ) O(mlogn) O(mlogn)(也有说 O ( m l o g m ) O(mlogm) O(mlogm)的)。 其原理是每次选择当前最短路最小的且没有选择过的点将其与其邻近点做松弛操作。

性质1:在选择某个点与其邻近点做松弛操作时能够保证当前选择的点的最短路已经求出。

正是性质1保证了Dijkstra算法的正确性。

正是性质1保证了Dijkstra算法过程中每个点只会选择一次。

正是性质1保证了Dijkstra算法的复杂度。

Dijkstra算法与负权边

如果存在负权边,那么性质1可能会被破坏,从而导致Dijkstra算法不能得到正确的结果,一个常见的例子如下:
在这里插入图片描述
s出发,计算出d[a]=3, d[b]=1,这时候会选择b进行下一次邻近点的松弛操作,明显发现此时d[b]=1并不是从s到达b的最短路(应该为s->a->b),因此性质1被破坏(正是因为存在负权边导致性质1不能得到保证),Dijkstra算法后续过程中会出现错误。

这也是为什么Dijkstra算法中需要使用used数组来标识某个点是否已经被选择,常见的堆优化Dijkstra算法大致如下:

q.push({0, s});
dis[s] = 0;
while (!q.empty()) {auto item = q.top();q.pop();int u = item.second;if (used[u]) { continue; }used[u] = true;for (auto edge : g[u]) {int v = edge.to, w = edge.w;if (dis[v] > dis[u] + w) {dis[v] = dis[u] + w;q.push({dis[v], v});}}
}

上面代码中used数组保证了每个点只被选择一次。

能否去掉每个点选择一次的限制

我们是否可以将used数组改成类似于SPFA里面的inq数组,也就是将上面的代码改成如下代码:

q.push({0, s});
inq[s] = 0;
while (!q.empty()) {auto item = q.top();q.pop();int u = item.second;inq[u] = false;for (auto edge : g[u]) {int v = edge.to, w = edge.w;if (dis[v] > dis[u] + w) {dis[v] = dis[u] + w;if (inq[v]) { continue; }inq[v] = true;q.push({dis[v], v});}}
}

进行上面的代码更改后的算法已经不能够叫做Dijkstra算法,应该叫做优先队列优化的SPFA算法,算法的正确性与SPFA算法是一致的,其复杂度也应该是与SPFA算法一致,可能会优秀一点。

代码

最后给出开篇两道题目的代码:
LuoguP3371
LuoguP4779

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

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

相关文章

Redis面试题汇总

目录 一、动力节点Redis的书 7. Redis持久化 二、马士兵李瑾老师 2.1 Redis高级特性和应用 1)发布订阅: 2)Stream 延伸:Redis中几种消息队列实现的总结 3)慢查询 4)Pipeline流水线 5)…

新发现!科学家最新成果:补充类“原知因起源金”物质可延长寿命23%

近日,美哥伦比亚大学Vijay Yadav团队在《Science》发布了一项重磅级成果:通过补充一种特殊氨基酸(带有磺酸基团的全能抗衰物质),竟然惊人地将实验动物的寿命延长了23%。 而其背后的机制,与早已火爆电商圈的…

Pygame基础9-射击

简介 玩家用鼠标控制飞机(白色方块)移动,按下鼠标后,玩家所在位置出现子弹,子弹匀速向右飞行。 代码 没有什么新的东西,使用两个精灵类表示玩家和子弹。 有一个细节需要注意,当子弹飞出屏幕…

erp系统开发报价:企业如何选择一套合适的智能erp管理系统-亿发

在选择ERP系统时,企业通常希望了解上一套系统到底需要多少资金,但实际上这个问题并没有一个明确的答案。一般的erp系统从几万到几百万不等,一些简单的erp系统甚至只需要几千元。ERP系统的价格取决于多种因素,包括企业的业务规模、…

vs2022断点找bug出错(打上100个断点)

初步分析:故障出自-具体功能模块 进一步分析:故障出自-该功能代码流程 进一步分析:从该功能起点-终点,一路打100个断点

【学习笔记】java项目—苍穹外卖day03

文章目录 苍穹外卖-day03课程内容1. 公共字段自动填充1.1 问题分析1.2 实现思路1.3 代码开发1.3.1 步骤一1.3.2 步骤二1.3.3 步骤三 1.4 功能测试1.5 代码提交 2. 新增菜品2.1 需求分析与设计2.1.1 产品原型2.1.2 接口设计2.1.3 表设计 2.2 代码开发2.2.1 文件上传实现2.2.2 新…

想要做好自动化测试,离不开这5点!

最近小编在逛技术交流社区,在一条讨论自动化测试落地面临的痛点及可以创造的价值下面,有这样一条回复颇有感触,分享如下: 如果你让两个相互不认识、来自不同公司的测试工程师自由讨论,我猜他两寒暄的第一个问题会是&a…

时序预测 | Python实现VMD-CNN-LSTM时间序列预测

时序预测 | Python实现VMD-CNN-LSTM时间序列预测 目录 时序预测 | Python实现VMD-CNN-LSTM时间序列预测预测效果基本介绍模型描述代码设计预测效果 基本介绍 VMD-CNN-LSTM 是一种混合深度学习模型,结合了变分模态分解(VMD)、卷积神经网络(CNN)和长短期记忆网络(LSTM)的…

阿里云优惠券如何领取使用?

阿里云是阿里巴巴旗下云计算及人工智能科技公司,提供云服务器、云数据库、云存储等云计算服务和云解决方案。为了吸引更多的用户,阿里云经常推出各种优惠活动,其中就包括阿里云优惠券。本文将为大家详细介绍阿里云优惠券领取方法及使用教程&a…

【Leetcode】top 100 二分查找

35 搜索插入位置 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。请必须使用时间复杂度为 O(log n) 的算法。 基础写法!!!牢记…

基于蚁群算法的三维路径规划(matlab实现)

作品简介 1 理论基础 1.1 三维路径规划问题概述 三维路径规划指在已知三维地图中,规划出一条从出发点到目标点满足某项指标最优,并且避开了所有三维障碍物的三维最优路径。现有的路径规划算法中,大部分算法是在二维规划平面或准二维规划平面…

OM6650AM支持蓝牙5.1协议栈与2.4GHz私有协议的双模无线连接SoC芯片

OM6650AM是一款超低功耗、同时支持蓝牙5.1协议栈与2.4GHz私有协议的双模无线连接SoC芯片,采用4.0 mm x 4.0 mm QFN32封装,具有丰富的资源,极低的功耗,优异的射频性能,可广泛应用于车载数字钥匙模组、胎压检测、PKE钥匙…