尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

题解:P4779 【模板】单源最短路径(标准版)

题解:P4779 【模板】单源最短路径(标准版)
📅 发布时间:2026/6/19 23:25:05

题目传送门

算法分析

本题要求计算单源最短路径,并且边权非负,适合使用Dijkstra 算法。Dijkstra 算法是一种贪心算法,用于计算带权有向图或无向图中单个源节点到所有其他节点的最短路径。

为什么选择 Dijkstra 算法?

  1. Dijkstra 算法要求所有边权非负。在本题中,题目明确说明边权 \(0 ≤ wi ≤ 10^9\),完全符合 Dijkstra 的应用条件。若存在负权边,Dijkstra 可能会得到错误结果,此时需使用 Bellman-Ford 或 SPFA 算法。

  2. 朴素实现:\(O (n²)\),适用于节点数较少的稠密图。
    优先队列优化:\(O ((m+n) logn)\),其中m为边数,n为节点数。本题数据范围为\(1 ≤ n ≤ 10^5\) 和 \(1 ≤ m ≤ 2×10^5\),使用优先队列优化后的 Dijkstra 可以高效处理。

  3. Dijkstra 算法是确定性算法,对于相同的输入,结果唯一且可预测。相比之下,某些近似算法或启发式算法(如 A*)可能需要额外信息(如启发函数),而 Dijkstra 仅依赖图的结构和边权。

  4. 本题要求计算从起点s到所有其他节点的最短路径,Dijkstra 算法正是为此场景设计。若仅需计算特定终点的最短路径,可在找到终点后提前终止算法。

本题为何不选择其他算法?

Floyd-Warshall 算法:时间复杂度 \(O (n³)\),适用于多源最短路径,但本题仅需求单源路径,使用该算法会导致超时。
Bellman-Ford/SPFA 算法:适用于含负权边的图,时间复杂度较高\((O (mn))\),在本题的非负权图中效率低于 Dijkstra。

注意事项

由于边权非负,Dijkstra 算法可以正确处理本题。
使用优先队列时,由于 C++ 的优先队列默认是最大堆,因此存储距离的负值来模拟最小堆。
初始化距离数组时,使用 \(2147483647\) 表示无穷大,避免溢出。

算法思路

  1. 初始化所有节点的距离为无穷大,起点的距离为\(0\)。
  2. 使用优先队列(最小堆)来维护待处理的节点,优先处理距离最小的节点。
  3. 每次从优先队列中取出距离最小的节点,遍历其所有邻接边,更新邻接节点的距离。
  4. 重复步骤3,直到优先队列为空。

代码实现

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<ext/pb_ds/priority_queue.hpp>
#define MP(x, y) make_pair(x, y)
#define Pair pair<int, int> 
using namespace std;
const int MAXN = 1e6 + 10, INF = 2147483646, B = 19;// 快速读入函数
inline int read() {char c = getchar(); int x = 0, f = 1;while(c < '0' || c > '9') {if(c == '-') f = 1; c = getchar();}while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();return x * f;
}int N, M, S;// 边的结构体
struct Edge {int u, v, w, nxt;
};
Edge E[MAXN];
int head[MAXN], num = 1;// 添加边
void AddEdge(int x, int y, int z) {E[num] = (Edge) {x, y, z, head[x]};head[x] = num++;
}int dis[MAXN], vis[MAXN];
priority_queue<Pair> q; // Dijkstra算法实现
void Dij() {// 初始化距离数组for(int i = 1; i <= N; i++) dis[i] = 2147483647;dis[S] = 0; q.push(MP(0, S));while(!q.empty()) {int p = q.top().second; q.pop();if(vis[p]) continue; vis[p] = 1;// 遍历当前节点的所有邻接边for(int i = head[p]; i != -1; i = E[i].nxt) {int to = E[i].v;// 松弛操作if(dis[to] > dis[p] + E[i].w) dis[to] = dis[p] + E[i].w,q.push(MP(-dis[to], to));}}// 输出结果for(int i = 1; i <= N; i++)printf("%d ", dis[i]);
}int main() {// 初始化头数组memset(head, -1, sizeof(head));// 读入数据N = read(); M = read(); S = read();for(int i = 1; i <= M; i++) {int x = read(), y = read(), z = read();AddEdge(x, y, z);}// 执行Dijkstra算法Dij();return 0;
}

代码解释

· 快速读入函数:由于输入数据量较大,使用快速读入函数可以提高效率。

· 邻接表存储图:使用结构体数组和头数组来存储图的邻接表,便于遍历每个节点的所有邻接边。

· Dijkstra 算法:使用优先队列优化的 Dijkstra 算法,每次取出距离最小的节点进行处理,并更新其邻接节点的距离。

· 松弛操作:对于每个邻接节点,如果通过当前节点到达该节点的距离更短,则更新该节点的距离。

复杂度分析

时间复杂度:\(O ((m + n) logn)\),其中 n 是节点数,m 是边数。

空间复杂度:\(O (m + n)\),主要用于存储图的邻接表和优先队列。

审核大大求过

"——敬不完美的明天" "——敬不再沉默的历史,热烈而勇敢的奔赴,和通往所以未来的旅途" "——敬盛会的邀请函,所有的谎言,和唯一的真相" "——敬坚忍的岁月,每个悲伤的夜晚,和终将到来的黎明" "——敬我的过去,现在,未来...和年少时至死不渝的梦" 时钟的指针转过一圈又一圈,但每一天的开始和结束,永远落在「前进」的十二点

相关新闻

  • 网关配置
  • 完整教程:docker创建postgreSql带多个init的sql
  • vscode的文心快码插件不错

最新新闻

  • TPA3255 Class D功放实战:从选型到调音的全链路设计指南
  • PingFangSC字体解决方案:跨平台中文显示一致性技术实现
  • KETTLE日志记录、任务巡检、邮件发送
  • FluentTerminal全屏模式技术深度解析:沉浸式终端体验的架构实现
  • 3.gemini336相机在ubuntu22.04的ros2下运行
  • 成本不到 5000 欧元!Matthias Plappert 公开在办公桌旁搭建机器人研究装置的研究过程

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号