当前位置: 首页 > news >正文

【算法磨剑:用 C++ 思考的艺术・Dijkstra 实战】弱化版 vs 标准版模板,洛谷 P3371/P4779 双题精讲

在这里插入图片描述
在这里插入图片描述

文章目录

  • 前言:
    • 《算法磨剑: 用C++思考的艺术》 专栏
    • 《C++:从代码到机器》 专栏
    • 《Linux系统探幽:从入门到内核》 专栏
  • 正文:
    • 1:[P3371 【模板】单源最短路径(弱化版](https://www.luogu.com.cn/problem/P3371)
      • 【解释】:
      • 【代码实现】:(大家会发现,这个代码⾮常像 prim 算法)
    • 2.堆优化版 dijkstra 算法
      • 【解释】:
      • [代码实现]:(其实 prim 算法也有⼀个堆优化的版本,但是时间复杂度和 kk 算法相差⽆⼏,因此没有讲解
  • 结语:

前言:

《算法磨剑: 用C++思考的艺术》 专栏

专注用C++破解算法面试真题,详解LeetCode热题,构建算法思维,从容应对技术挑战。

👉 点击关注专栏


《C++:从代码到机器》 专栏

深入探索C++从语法特性至底层原理的奥秘,构建坚实而深入的系统编程知识体系。

👉 点击关注专栏


《Linux系统探幽:从入门到内核》 专栏

深入Linux操作系统腹地,从命令、脚本到系统编程,探索Linux的运作奥秘。

👉 点击关注专栏


作者:孤廖
学习方向:C++/Linux/算法
人生格言:折而不挠,中不为下

正文:

1:P3371 【模板】单源最短路径(弱化版

【解释】:

常规版 dijkstra 算法
Dijkstra 算法是基于贪⼼思想的单源最短路算法,求解的是"⾮负权图"上单源最短路径。
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/983e9a93ab69442994f4cd4454995e40.png

常规版 dijkstra 算法流程:

  • 准备⼯作:
  • 创建⼀个⻓度为 n 的 dist 数组,其中 dist[i] 表⽰从起点到 i 结点的最短路;
  • 创建⼀个⻓度为 n 的 bool 数组 st ,其中 st[i] 表⽰ i 点是否已经确定了最短路。

• 初始化: dist[1] = 0 ,其余结点的 dist 值为⽆穷⼤,表⽰还没有找到最短路。

  • 重复:在所有没有确定最短路的点中,找出最短路⻓度最⼩的点 u 。打上确定最短路的标记,然后对 u 的出边进⾏松弛操作
  • 重复上述操作,直到所有点的最短路都确定

【代码实现】:(大家会发现,这个代码⾮常像 prim 算法)

算法磨剑专栏里的 最小生成树中所提及
点击这里跳转

#define _CRT_SECURE_NO_WARNINGS
//P3371 【模板】单源最短路径(弱化版) (模板)
//时间复杂度 o(n^2+m)即o(n^2)#include <iostream>
#include <vector>
using namespace std;
const int N = 1e4 + 10,INF= 2147483647;
typedef pair<int,int> PII;
int n, m, s;//点的个数,边的个数,起源点数
vector<PII> edges[N];//edges[i]:与i点为起点  出边的信息
int dist[N];//dist[i]:起源点到点i的最短路径
bool st[N];//st[i]:点i是否确定起源点到该点的最短路径
void dijkstra()
{//初始化for (int i = 0; i <= n; i++) dist[i] = INF;dist[s] = 0;//每次从没确定最短路径的点中找到最小的路径点即认为起源点到该点//路径已经确定为最小(贪心)//贪心解释:从未确定点中找到的最小点为什么就可以确定起源点到该点的路径最小?//因为其他未确定且能和最小点有路径可能的这些点,本身起源点到这些未确定的点//的路径就已经大于起源点到最小点的路径了 ,所以这些未确定的点没有更小的路径使得//最小点到 起源点的路径大小做出改变(所以这种算法的贪心思想不能用于边权有负数的有向图)for (int i = 1; i < n; i++)//确定n-1个点即n个点全部确定完成{int a = 0;//最小点的下标for (int j = 1; j <= n; j++){if (!st[j] && dist[j] < dist[a])a = j;}//标记最小点 并进行松弛操作st[a] = true;for (auto& e : edges[a]){int b = e.first;//出边接受点int c = e.second;//a~b的边权//更新出边接受点可能的最小路径长度dist[b] = min(dist[b], dist[a] + c);}}//输出结果 遍历dist 数组for (int i = 1; i <= n; i++) cout << dist[i] << " ";}
int main()
{cin >> n >> m >> s;//输入边的信息for (int i = 1; i <= m; i++){int u, v, z;//u->v 的边权zcin >> u >> v >> z;edges[u].push_back({ v,z });}dijkstra();return 0;
}

时间复杂度为o(n^2)

本算法以及后面几篇关于单源最短路径的算法 关于贪心思想的证明 均不做阐述,感兴趣的可以看下《算法导论》这本书

2.堆优化版 dijkstra 算法

【解释】:

堆优化版的 dijkstra 算法流程

  • 准备⼯作:
  • 创建⼀个⻓度为 n 的 dist 数组,其中 dist[i] 表⽰从起点到 i 结点的最短路;
  • 创建⼀个⻓度为 n 的 bool 数组 st ,其中 st[i] 表⽰ i 点是否已经确定了最短路;
  • 创建⼀个⼩根堆,维护更新后的结点。(也就是需要确定最短路的结点)
  • 初始化: dist[1] = 0 ,然后将 {0, s} 加到堆⾥;其余结点的 dist 值为⽆穷⼤,表⽰还没有找到最短路。

{0,s}即{距离,点} 为什么这么设计? 因为greater这个容器比较的是一个参数

  • 重复:弹出堆顶元素,如果该元素已经标记过,就跳过;如果没有标记过,打上标记,进⾏松弛操作。
  • 重复上述操作,直到堆⾥⾯没有元素为⽌。

[代码实现]:(其实 prim 算法也有⼀个堆优化的版本,但是时间复杂度和 kk 算法相差⽆⼏,因此没有讲解

感兴趣的可以自行实现

#define _CRT_SECURE_NO_WARNINGS
//【模板】单源最短路径(标准版)#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
const int N = 1e5 + 10;
typedef pair<int, int> PII;
int n, m, s;
vector<PII> edges[N];
priority_queue<PII, vector<PII>, greater<PII>> heap;//小根堆{距离,节点}
int dist[N];
bool st[N];
void dijkstra()
{//初始化memset(dist, 0x3f3f3f, sizeof dist);dist[s] = 0;heap.push({ 0,s });//从未确定的点中找到最小的点while (heap.size()){int a = heap.top().second;//最小点heap.pop();if (st[a]) continue;//避免拿到确定点之前的较大路径的情况st[a] = true;//将点a的出边进行松弛操作for (auto& e : edges[a]){int b = e.first;int z = e.second;if (dist[a] + z < dist[b]){dist[b] = dist[a] + z;heap.push({ dist[b],b });}}}//输出结果for (int i = 1; i <= n; i++) cout << dist[i] << " ";
}
int main()
{cin >> n >> m >> s;//输入边的信息for (int i = 1; i <= m; i++){int u, v, z;cin >> u >> v >> z;edges[u].push_back({ v,z });}dijkstra();return 0;
}



结语:

这篇 “算法磨剑:用 C++ 思考的艺术”,我们把 Dijkstra 的 “弱化版(朴素)”和“标准版(堆优化)”模板在洛谷双题里 “磨” 透了 ——P3371 用 “三重循环 + 暴力找最小距离”,让你看清算法的 “原始逻辑骨架”;P4779 靠 C++ 的priority_queue实现堆优化,把时间复杂度从(O(n^2))直接压到(O(m\log n)),完美适配 “大规模稀疏图” 的实战场景。两种模板的核心差异,本质是“找「最小距离节点」的效率迭代”,而 C++ 的 STL 容器(vector建邻接表、priority_queue维护候选节点),则是让 “思路” 落地为 “高效代码” 的关键工具

不过,Dijkstra 并非 “单源最短路” 的全部答案 —— 它天生解决不了含负权边的图,更没法直接检测 “负环”(能无限缩短路径的环)。那遇到负权边怎么办?如何高效判断图里有没有负环?天的专栏,会带来Bellman-Ford 算法、SPFA 算法,还有BF 算法判断负环的技巧,它们能补上 Dijkstra 的 “短板”,覆盖更复杂的图论场景

如果今天的 Dijkstra 双模板解析,帮你理清了 “不同规模图下的实现选择”,不妨点个赞 + 收藏,方便后续对比复习;也欢迎在评论区交流:你用朴素 Dijkstra 时,有没有被 “三重循环” 搞晕过?堆优化的priority_queue在 C++ 里,有没有踩过 “类型匹配 / 自定义比较” 的坑?带着对 “负权边、负环” 的好奇,我们明天继续 “磨” 单源最短路的其他算法,看看它们如何和 Dijkstra 形成 “算法全家桶”~


文章转载自:

http://GHMAfAJO.cxryx.cn
http://9gCcugsC.cxryx.cn
http://YlFyETeA.cxryx.cn
http://6HlfAjck.cxryx.cn
http://QMSq57xp.cxryx.cn
http://5WKbREUz.cxryx.cn
http://Yq8AgkE9.cxryx.cn
http://U7XS2O2M.cxryx.cn
http://pEQ8fzGV.cxryx.cn
http://kbkxxERK.cxryx.cn
http://9oSPf5bf.cxryx.cn
http://7KzHRIBl.cxryx.cn
http://uqW6DP1p.cxryx.cn
http://KoF2yTJ1.cxryx.cn
http://tU7ZKoas.cxryx.cn
http://B2iB7a0b.cxryx.cn
http://QICtmoHg.cxryx.cn
http://KQX2Kx1S.cxryx.cn
http://Qy5ENxkX.cxryx.cn
http://z8LgEBHc.cxryx.cn
http://brXYClIX.cxryx.cn
http://RTzW3ZxP.cxryx.cn
http://0pIJz0gO.cxryx.cn
http://S7ycnzPC.cxryx.cn
http://ZzRUIRcb.cxryx.cn
http://9xLjpIpB.cxryx.cn
http://7ooEsI1A.cxryx.cn
http://xAlAcQgR.cxryx.cn
http://KWH4FQ80.cxryx.cn
http://mE4IUZrr.cxryx.cn
http://www.dtcms.com/a/379889.html

相关文章:

  • Java大厂面试实录:产业互联网大数据与AI服务场景下的微服务与智能搜索(含详细解读)
  • 苍穹外卖项目笔记day08
  • 智能逗猫球方案MCU控制方案浅析-智能宠物玩具,宠物解闷神器
  • Unity键盘控制角色运动
  • 大数据毕业设计-基于Spark的全国高速公路实时路况融合与拥堵预测系统(高分计算机毕业设计选题·定制开发·真正大数据)
  • zmq源码分析之session
  • Xcode 上传 ipa 全流程详解 App Store 上架流程、uni-app 生成 ipa 文件上传与审核指南
  • Java 泛型详解:从基础到高级应用
  • 第6.2节 Android Agent开发<二>
  • ubuntu挂载新硬盘的方法
  • Kubernetes Ingress:使用 Apache APISIX 进行外部流量路由
  • 初学者如何选择适合的云平台进行AIGC训练?
  • Docker存储卷(Volume)完全指南:从入门到精通
  • STM32-FreeRTOS操作系统-二值信号量与计数信号量
  • 蒸面器/蒸脸仪方案开发,蒸面器/蒸脸仪MCU控制方案分析
  • 容器技术崛起:从PaaS到Docker的变革探问
  • 如何定位Mysql慢查询和短而频的查询
  • 机器学习的基本流程:从数据到模型
  • springboot rabbitmq 消息队列入门与实战
  • 使用vllm部署neo4j的text2cypher-gemma-2-9b-it-finetuned-2024v1模型
  • 栈-844.比较含退格的字符串-力扣(LeetCode)
  • [Dify] HTTP 请求节点详解:如何在 Dify 中配置与调用第三方 API
  • SQL优化简单思路
  • 构建AI智能体:三十一、AI医疗场景实践:医学知识精准问答+临床智能辅助决策CDSS
  • HTTP的Web服务测试在Python中的实现
  • 华为HCIE-云计算培训课程有哪些?
  • 绕过 FlashAttention-2 限制:在 Turing 架构上使用 PyTorch 实现 FlashAttention
  • 美食分享|基于Springboot和vue的地方美食分享网站系统设计与实现(源码+数据库+文档)
  • 华为HICE云计算的含金量高吗?
  • 【算法--链表】146.LRU缓存--通俗讲解