代码随想录算法训练营 Day59 图论Ⅸ dijkstra优化版 bellman_ford

article/2025/8/21 20:39:44

图论

题目

47. 参加科学大会(第六期模拟笔试)
改进版本的 dijkstra 算法(堆优化版本)
朴素版本的 dijkstra 算法解法的时间复杂度为 O ( n 2 ) O(n^2) O(n2) 时间复杂度与 n 有关系,与边无关系
类似于 prim 对应点多的情况,kruskal 对应边多的情况
Djkstra 也可以着重于边,着重于边那么存储结构使用邻接表实现
优化的方法是:将边加入小顶堆中实现自动排序(最小边在堆顶),每次从堆顶取边即可
堆实现的三部曲,由于邻接表的存在不需要 for 循环遍历可能的边了,因此有如下代码
1. 第一步,选择原点到节点最近且未访问过的边,pair<节点编号,源点到该节点的权值>
我们不用 for 循环去遍历,直接取堆顶元素:
pair<int, int> cur = pq.Top (); pq.Pop ();
2. 第二步,选择最近节点标记访问过
Visited[cur. First] = true;
3. 第三步,更新非访问节点到原点距离(minDist 数组)
所以在邻接表中,我们要获取节点 cur 链接指向哪些节点,就是遍历 grid[cur 节点编号] 这个链表
cur.first 就是cur节点编号,参考上面pair的定义: pair<节点编号,源点到该节点的权值>
接下来就是更新非访问节点到源点的距离

// 3. 第三步,更新非访问节点到源点的距离(即更新minDist数组)
for (Edge edge : grid[cur.first]) { // 遍历 cur指向的节点,cur指向的节点为 edge// cur指向的节点edge.to,这条边的权值为 edge.valif (!visited[edge.to] && minDist[cur.first] + edge.val < minDist[edge.to]) { // 更新minDistminDist[edge.to] = minDist[cur.first] + edge.val;pq.push(pair<int, int>(edge.to, minDist[edge.to]));}
}

在这里插入图片描述

完整代码实现

#include <iostream>
#include <vector>
#include <list>
#include <queue>
#include <climits>using namespace std;// 小顶堆
class MyCmp {
public:bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {return lhs.second > rhs.second;}
};struct Edge {int to; // 邻接顶点int val; // 边权重Edge(int t, int w): to(t), val(w) {} // 构造函数
};int main() {int n, m, x, y, val;cin >> n >> m;// 构造邻接表vector<list<Edge>> grid(n+1);vector<int> minDist(n+1, INT_MAX);vector<bool> vis(n+1, false);for (int i = 0; i < m; ++i) {cin >> x >> y >> val;grid[x].push_back(Edge(y, val));}int start = 1;int end = n;// 构造最小堆 存放pair<节点,节点到该节点的权值>// 参数1 存储元素类型 参数2 容器底层实现 参数3自定义比较函数priority_queue<pair<int, int>, vector<pair<int, int>>, MyCmp> pq;// 队列初始化为0pq.push(pair<int, int>(start, 0));minDist[start] = 0; // 起点距离0while (!pq.empty()) {// 1. 第一步选择原点到节点最近且未被访问过的点pair<int, int> cur = pq.top();pq.pop();if (vis[cur.first]) continue;// 2.标记访问过vis[cur.first] = true;// 3.更新非访问节点到原点距离for (Edge e : grid[cur.first]) {// 获得当前节点指向的节点// cur指向节点e.to 边权值未e.valif (!vis[e.to] && minDist[cur.first] + e.val < minDist[e.to]) {minDist[e.to] = minDist[cur.first] + e.val;pq.push(pair<int, int>(e.to, minDist[e.to]));}}}if (minDist[end] == INT_MAX) cout << -1 << endl;else cout << minDist[end] << endl;
}

94. 城市间货物运输 I
Bellman_ford 算法介绍,本体不同于上面 dijkstra,此时的权重存在负数
Bellman_ford算法的核心思想是对所有边进行松弛n-1次操作(n为节点数量)从而求得目标最短路
不断尝试更新所有的边,直到所有可能的路径都被找到
什么是松弛?举个例子
每条边有起点、终点和边的权值。例如一条边,节点A 到节点B 权值为value,如图:![[Day59 图论Ⅸ dijkstra优化版-250529-1.png|500]]
minDist[B] 表示 到达B节点 最小权值,minDist[B] 有哪些状态可以推出来?
状态一: minDist[A] + value 可以推出minDist[B]
状态二: minDist[B] 本身就有权值 (可能是其他边链接的节点B 例如节点C,以至于 minDist[B] 记录了其他边到 minDist[B] 的权值)如何确定 minDist[B]
本题我们要求最小权值,那么 这两个状态我们就取最小的
if (minDist[B] > minDist[A] + value) minDist[B] = minDist[A] + value
也就是说,如果通过 A 到 B 这条边可以获得更短的到达B节点的路径,即如果 minDist[B] > minDist[A] + value,那么我们就更新 minDist[B] = minDist[A] + value 这个过程就叫做 “松弛
以上讲了这么多,其实都是围绕以下这句代码展开:这句代码就是 Bellman_ford算法的核心操作
if (minDist[B] > minDist[A] + value) minDist[B] = minDist[A] + value
也可以这样写
minDist[B] = min(minDist[A] + value, minDist[B])
其实 Bellman_ford算法也是采用了动态规划的思想,即:将一个问题分解成多个决策阶段,通过状态之间的递归关系最后计算出全局最优解。
那么为什么是 n - 1次松弛呢?这里要给大家模拟一遍 Bellman_ford 的算法才行,接下来我们来看看对所有边松弛 n - 1 次的操作是什么样的。
模拟过程
初始化过程。起点为节点1,起点到起点的距离为0,所以 minDist[1] 初始化为0

其他节点对应的minDist初始化为max,因为我们要求最小距离,那么还没有计算过的节点默认是一个最大数,这样才能更新最小距离。对所有边进行第一次松弛。
接下来我们来松弛一遍所有的边。边:节点5 -> 节点6,权值为-2 ,minDist[5] 还是默认数值max,所以不能基于节点5 去更新节点6
在这里插入图片描述

边:节点1 -> 节点2,权值为1 ,minDist[2] > minDist[1] + 1 ,更新 minDist[2] = minDist[1] + 1 = 0 + 1 = 1
在这里插入图片描述

边:节点5 -> 节点3,权值为1 ,minDist[5] 还是默认数值max,所以不能基于节点5去更新节点3
在这里插入图片描述

边:节点2 -> 节点5,权值为2 ,minDist[5] > minDist[2] + 2 (经过上面的计算minDist[2]已经不是默认值,而是 1),更新 minDist[5] = minDist[2] + 2 = 1 + 2 = 3
在这里插入图片描述

边:节点2 -> 节点4,权值为-3 ,minDist[4] > minDist[2] + (-3),更新 minDist[4] = minDist[2] + (-3) = 1 + (-3) = -2
在这里插入图片描述

边:节点4 -> 节点6,权值为4 ,minDist[6] > minDist[4] + 4,更新 minDist[6] = minDist[4] + 4 = -2 + 4 = 2
在这里插入图片描述

边:节点1 -> 节点3,权值为5 ,minDist[3] > minDist[1] + 5 更新 minDist[3] = minDist[1] + 5 = 0 + 5 = 5
在这里插入图片描述

以上是对所有边进行一次松弛之后的结果。
那么需要对所有边松弛几次才能得到 起点(节点1) 到终点(节点6)的最短距离呢?
对所有边松弛一次,相当于计算起点到达与起点一条边相连的节点的最短距离
注意我上面讲的是 对所有边松弛一次,相当于计算 起点到达 与起点一条边相连的节点 的最短距离,这里 说的是 一条边相连的节点。
与起点(节点1)一条边相邻的节点,到达节点2 最短距离是 1,到达节点3 最短距离是5。
而 节点1 -> 节点2 -> 节点5 -> 节点3 这条路线 是 与起点 三条边相连的路线了。
所以对所有边松弛一次 能得到 与起点 一条边相连的节点最短距离。
那对所有边松弛两次 可以得到与起点 两条边相连的节点的最短距离。
那对所有边松弛三次 可以得到与起点 三条边相连的节点的最短距离,这个时候,我们就能得到到达节点3真正的最短距离,也就是 节点1 -> 节点2 -> 节点5 -> 节点3 这条路线。
那么再回归刚刚的问题,需要对所有边松弛几次才能得到 起点(节点1) 到终点(节点6)的最短距离呢?节点数量为n,那么起点到终点,最多是 n-1 条边相连。
那么无论图是什么样的,边是什么样的顺序,我们对所有边松弛 n-1 次 就一定能得到 起点到达 终点的最短距离。
其实也同时计算出了,起点到达所有节点的最短距离,因为所有节点与起点连接的边数最多也就是 n-1 条边。

#include <iostream>
#include <vector>
#include <list>
#include <climits>using namespace std;int main() {int n, m, x, y, val;cin >> n >> m;// 使用朴素存储图vector<vector<int>> grid;for (int i = 0; i < m; ++i) {cin >> x >> y >> val;grid.push_back({x, y, val});}int start = 1;int end = n;vector<int> minDist(n+1, INT_MAX);minDist[start] = 0;// 对所有边松弛n-1次for (int i = 1; i < n; ++i) {// 每一次松弛是对所有边松弛for (vector<int>& side : grid) {int from = side[0];int to = side[1];int price = side[2];// 松弛操作if (minDist[from] != INT_MAX && minDist[to] > minDist[from] + price) {minDist[to] = minDist[from] + price;}}}if (minDist[end] == INT_MAX) cout << "unconnected" << endl;else cout << minDist[end] << endl;return 0;
}

http://www.hkcw.cn/article/uvcWoyjyxt.shtml

相关文章

Webots R2025a和ROS2 Jazzy部分资料汇总-250529

使用注意要点&#xff1a; 安装webot-ros包&#xff1a; sudo apt install ros-jazzy-webots-ros2 sudo apt install ros-jazzy-webots-ros2 sudo apt install ros-jazzy-webots-ros2 Reading package lists... Done Building dependency tree... Done Reading state infor…

jdbcTemplate防止注入写法

前一期写过拼接查询 https://blog.csdn.net/qq_44749121/article/details/148084689 但是会涉及到注入风险 所幸这一期给一个改进写法 在 Spring 框架中使用 JdbcTemplate 时&#xff0c;可以通过以下方式有效防止 SQL 注入&#xff1a; 1. 使用预编译语句&#xff08;Prepare…

Spring AI 系列3: Promt提示词

一、Promt提示词 Promt提示是引导 AI 模型生成特定输出的输入&#xff0c; 提示的设计和措辞会显著影响模型的响应。 在 Spring AI 中与 AI 模型交互的最低层级&#xff0c;处理提示有点类似于在 Spring MVC 中管理”视图”。 这涉及创建带有动态内容占位符的大段文本。 这些占…

用 Python 模拟雪花飘落效果

用 Python 模拟雪花飘落效果 雪花轻轻飘落&#xff0c;给冬日带来一份浪漫与宁静。本文将带你用一份简单的 Python 脚本&#xff0c;手把手实现「雪花飘落效果」动画。文章深入浅出&#xff0c;零基础也能快速上手&#xff0c;完整代码仅需一个脚本文件即可运行。 目录 前言…

Linux `cp` 命令深度解析与高阶应用指南

Linux `cp` 命令深度解析与高阶应用指南 一、核心功能解析1. 基本作用2. 与类似命令对比二、选项系统详解1. 基础选项矩阵2. 高阶选项说明三、高阶应用场景1. 企业数据备份2. 容器环境部署3. 系统安全审计四、特殊文件处理1. 符号链接处理2. 稀疏文件优化五、性能优化策略1. 大…

中国寻亲网宣布将关闭服务器 25年终落幕

近日,中国寻亲网发布公告称将于2025年7月15日起停止运行并关闭服务器。公告于2025年4月1日发布,内容提到根据公司股东大会决议,公司将停止全部业务并进行注销。自2025年5月1日起,中国寻亲网将不再发布新的寻亲信息,仅提供原有信息的更改服务,直至最终关闭。对于无法继续为…

Spring代理工厂类ProxyFactory作用以及实现原理

代理工厂类ProxyFactory AdvisedSupport&#xff08;代理配置信息类&#xff09;ProxyFactory&#xff08;代理工厂类&#xff09;小结测试 源码见&#xff1a;mini-spring 在 AOP&#xff08;面向切面编程&#xff09;中&#xff0c;Spring 支持两种常见的代理机制&#xff1a…

旺店通ERP集成金蝶ERP(金蝶EAS、KIS、K3、云星空、云星辰、云星瀚)

对接说明 旺店通ERP完成所有供应链业务单向同步到金蝶ERP进行成本核算和生成财务凭证&#xff1a; 旺店通ERP货品数据同步至金蝶ERP物料档案旺店通ERP供应商数据同步至金蝶ERP供应商档案旺店通ERP店铺数据同步至金蝶ERP客户档案旺店通ERP仓库数据同步至金蝶ERP仓库档案旺店通…

美国年轻人遭遇“求职寒冬” 就业市场冻结

5月23日,美国加利福尼亚州奥兰治,查普曼大学毕业生参加了毕业典礼。从5月到6月,美国大学迎来了毕业季。来自政府、研究机构和招聘平台的数据揭示了一个令年轻人不安的事实:求职者,尤其是职场新人,面临异常激烈的就业市场。CNBC报道指出,应届毕业生发现劳动力市场比几个月…

俄罗斯一副市长遭人肉炸弹袭击死亡 俄乌冲突背景下的悲剧

俄罗斯一副市长遭人肉炸弹袭击死亡 俄乌冲突背景下的悲剧!5月28日,俄罗斯斯塔夫罗波尔市副市长古尔齐耶夫遭遇爆炸袭击身亡。事发时,一名熟人走近古尔齐耶夫,随后该熟人携带的包发生爆炸。爆炸导致34岁的古尔齐耶夫和29岁的熟人身亡,这名男子在事发地附近租了一套公寓。古…

ArkUI(方舟UI框架)介绍

ArkUI&#xff08;方舟UI框架&#xff09;介绍 构建快速入门 使用ArkWeb构建页面

对话云蝠智能魏佳星:大模型呼叫如何重塑智能营销未来?

在数字化浪潮席卷全球的当下&#xff0c;智能营销已然成为企业角逐市场的关键 “武器”。而云蝠智能&#xff0c;作为行业内的 “弄潮儿”&#xff0c;正凭借创新技术引领着这一领域的变革。近日&#xff0c;我们有幸与云蝠智能创始人魏佳星展开深度对话&#xff0c;一同探寻云…

3条警犬退役训导员湿了眼眶 无言战友光荣卸甲

“立正!敬礼!”猎狐、涛涛、巴依从今天开始光荣退役。感谢它们用忠诚和无畏为昭通公安做出的突出贡献。近日,在云南省昭通市公安局警犬基地训练场上,民警辅警庄严敬礼,向三位特殊的战友——警犬“猎狐”“涛涛”“巴依”致以最高礼遇。这场催人泪下的退役仪式为它们的职业…

聊聊 Metasploit 免杀

各位小伙伴们&#xff0c;晚上好&#xff01; 咱们今天打开宵夜“安全食材箱”&#xff0c;聊聊渗透测试绕过杀毒&#xff08;免杀&#xff09;的那些门道。你可以把免杀理解为——深夜做宵夜时&#xff0c;家里有人睡觉&#xff0c;但你非得去厨房整点美食&#xff0c;还不能…

4 串电池保护芯片创芯微CM1341-DAT使用介绍

特性 专用于 4 串锂/铁/钠电池的保护芯片&#xff0c;内置有高精度电压检测电路和电流检测电路。通过检测各节电池的电压、充放电电流及温度等信息&#xff0c;实现电池过充电、过放电、均衡、断线、低压禁充、放电过电流、短路、充电过电流和过温保护等功能&#xff0c;放电过…

SAP销售订单批导创建

一、功能描述 用户导出极简的导入模板,并填写相关业务数据,后导入SAP,系统读取文件,并进行前端展示,通过程序进行测试执行,无误后保存生成的销售订单 二、FS简介 FS包含前端界面,功能设计与字段写入逻辑 前端界面 功能设计 写入字段 三、代码片段 获取ALV中的鼠…

【AI预测】5月30日尼克斯大战前瞻:东部黑马能否再下一城?

&#x1f3c0; 随着赛季进入白热化阶段&#xff0c;5月30日尼克斯的这场比赛注定焦点十足。作为东部近年来少有的“黑马型”球队&#xff0c;尼克斯用硬朗的防守和团队配合让人重新认识了这支老牌劲旅。 这篇文章&#xff0c;我们将从数据模型球员表现战术执行力三个维度&…

李翔担任北京女篮主教练 挖掘内部潜力

北京首钢篮球俱乐部于5月29日宣布,原北京首钢男篮助理教练李翔将担任北京首钢女篮主教练。在2024-2025赛季中国女子篮球联赛(WCBA)中,北京首钢女篮止步季后赛首轮,球队正积极备战全运会和新赛季的比赛。北京首钢篮球俱乐部常务副总经理张云松指出,任命李翔为女篮主教练旨…

永坤黄金出现大规模兑付异常 投资者损失惨重

5月15日,林明像往常一样打开永坤黄金的线上平台,点击“黄金提现”按钮。按照以往三年的操作,资金会在交易发生日后第三个工作日到账。然而到了5月20日,他的银行账户仍未收到款项。与此同时,投资者婷婷也被业务员告知她在线下购买的永坤黄金可能无法提取。2025年初,她在永…

《Pytorch深度学习实践》ch1-线性模型

------B站《刘二大人》 1.Machine Learning 训练集&#xff0c;测试集&#xff1b;开发集&#xff1a;将训练集拆分为&#xff08;训练集&#xff0c;开发集&#xff09;&#xff0c;用来测试泛化的能力&#xff0c;模型的评估&#xff1b;监督学习&#xff1a;利用一组已知类…