【C++】深入浅出“图”——最短路径算法

【C++】深入浅出“图”——最短路径算法

文章目录

一、Dijkstra算法

最短路径问题是指,从在带权的有向图中从某一顶点出发,找到通往另一顶点的最短路径,“最短”指的是沿路径各边的权值总和最小。

Dijkstra算法是单源最短路径的经典贪心算法,只能用于没有负权的图。它从起点出发,每次选当前距离最小且未确定最短路径的节点,用它去松弛(更新)所有邻接点的最短路径估计值,标记该节点为 “已确定”,重复此过程直到所有节点处理完毕,最终得到起点到图中所有节点的最短路径。

在这里插入图片描述
// src是选定的起点,dist记录起点到各点的最短路径,pPath记录到每个点的最短路径的前驱顶点下标voidDijkstra(const V& src, vector<W>& dist, vector<int>& pPath){ size_t srci =GetVertexIndex(src); size_t n = _vertexs.size(); dist.resize(n, MAX_W); pPath.resize(n,-1); dist[srci]=0; pPath[srci]= srci;// 已经确定最短路径的顶点集合 vector<bool>S(n,false);for(size_t j =0; j < n;++j){// 选最短路径顶点且不在S更新其他路径int u =0; W min = MAX_W;for(size_t i =0; i < n;++i){if(S[i]==false&& dist[i]< min){ u = i; min = dist[i];}} S[u]=true;// 松弛更新u连接顶点v srci->u + u->v < srci->v 更新for(size_t v =0; v < n;++v){if(S[v]==false&& _matrix[u][v]!= MAX_W && dist[u]+ _matrix[u][v]< dist[v]){ dist[v]= dist[u]+ _matrix[u][v]; pPath[v]= u;}}}}

二、Bellman_Ford算法

Bellman_Ford算法能用来解决负权图的单源最短路径问题,但是它的时间复杂度高于Dijkstra算法,本质是暴力求解。从起点出发,把图里所有边从头到尾松弛一遍,重复n次,就能算出起点到所有点的最短路径;因为任何最短路径最多只经过n‑1条边。跑完之后再扫一遍所有边,如果还能更新距离,就说明图里有负权回路,最短路径不存在。

在这里插入图片描述
boolBellmanFord(const V& src, vector<W>& dist, vector<int>& pPath){ size_t n = _vertexs.size(); size_t srci =GetVertexIndex(src);// vector<W> dist,记录srci-其他顶点最短路径权值数组 dist.resize(n, MAX_W);// vector<int> pPath 记录srci-其他顶点最短路径父顶点数组 pPath.resize(n,-1);// 先更新srci->srci为缺省值 dist[srci]=W();// 总体最多更新n轮for(size_t k =0; k < n;++k){// i->j 更新松弛bool update =false; cout <<"更新第:"<< k <<"轮"<< endl;for(size_t i =0; i < n;++i){for(size_t j =0; j < n;++j){// srci -> i + i ->jif(_matrix[i][j]!= MAX_W && dist[i]!= MAX_W && dist[i]+ _matrix[i][j]< dist[j]){ update =true;//cout << _vertexs[i] << "->" << _vertexs[j] << ":" << _matrix[i][j] << endl; dist[j]= dist[i]+ _matrix[i][j]; pPath[j]= i;}}}// 如果这个轮次中没有更新出更短路径,那么后续轮次就不需要再走了if(update ==false){break;}}// 还能更新就是带负权回路for(size_t i =0; i < n;++i){for(size_t j =0; j < n;++j){// srci -> i + i ->jif(_matrix[i][j]!= MAX_W && dist[i]+ _matrix[i][j]< dist[j]){returnfalse;}}}returntrue;}

三、Floyd_Warshall算法

Floyd-Warshall算法是求任意两点之间最短路径的算法,依次把每个点当作中转点,判断从 i 到 j 是直接走更近,还是经过这个中转点 k 再走更近,不断更新所有点对的最短距离,三层循环跑完就得到全图最短路径。

voidFloydWarshall(vector<vector<W>>& vvDist, vector<vector<int>>& vvpPath){ size_t n = _vertexs.size(); vvDist.resize(n); vvpPath.resize(n);// 初始化权值和路径矩阵for(size_t i =0; i < n;++i){ vvDist[i].resize(n, MAX_W); vvpPath[i].resize(n,-1);}// 直接相连的边更新一下for(size_t i =0; i < n;++i){for(size_t j =0; j < n;++j){if(_matrix[i][j]!= MAX_W){ vvDist[i][j]= _matrix[i][j]; vvpPath[i][j]= i;}if(i == j){ vvDist[i][j]=W();}}}// 最短路径的更新i-> {其他顶点} ->jfor(size_t k =0; k < n;++k){for(size_t i =0; i < n;++i){for(size_t j =0; j < n;++j){// k 作为的中间点尝试去更新i->j的路径if(vvDist[i][k]!= MAX_W && vvDist[k][j]!= MAX_W && vvDist[i][k]+ vvDist[k][j]< vvDist[i][j]){ vvDist[i][j]= vvDist[i][k]+ vvDist[k][j];// 找跟j相连的上一个邻接顶点// 如果k->j 直接相连,上一个点就k,vvpPath[k][j]存就是k// 如果k->j 没有直接相连,k->...->x->j,vvpPath[k][j]存就是x vvpPath[i][j]= vvpPath[k][j];}}}}}

Read more

【OpenClaw从入门到精通】第10篇:OpenClaw生产环境部署全攻略:性能优化+安全加固+监控运维(2026实测版)

【OpenClaw从入门到精通】第10篇:OpenClaw生产环境部署全攻略:性能优化+安全加固+监控运维(2026实测版)

摘要:本文聚焦OpenClaw从测试环境走向生产环境的核心痛点,围绕“性能优化、安全加固、监控运维”三大维度展开实操讲解。先明确生产环境硬件/系统选型标准,再通过硬件层资源管控、模型调度策略、缓存优化等手段提升响应速度(实测响应效率提升50%+);接着从网络、权限、数据三层构建安全防护体系,集成火山引擎安全方案拦截高危操作;最后落地TenacitOS可视化监控与Prometheus告警体系,配套完整故障排查清单和虚拟实战案例。全文所有配置、代码均经实测验证,兼顾新手入门实操性和进阶读者的生产级部署需求,帮助开发者真正实现OpenClaw从“能用”到“放心用”的跨越。 优质专栏欢迎订阅! 【DeepSeek深度应用】【Python高阶开发:AI自动化与数据工程实战】【YOLOv11工业级实战】 【机器视觉:C# + HALCON】【大模型微调实战:平民级微调技术全解】 【人工智能之深度学习】【AI 赋能:Python 人工智能应用实战】【数字孪生与仿真技术实战指南】 【AI工程化落地与YOLOv8/v9实战】【C#工业上位机高级应用:高并发通信+性能优化】 【Java生产级避坑指南:

By Ne0inhk
ARM Linux 驱动开发篇--- Linux 并发与竞争实验(互斥体实现 LED 设备互斥访问)--- Ubuntu20.04互斥体实验

ARM Linux 驱动开发篇--- Linux 并发与竞争实验(互斥体实现 LED 设备互斥访问)--- Ubuntu20.04互斥体实验

🎬 渡水无言:个人主页渡水无言 ❄专栏传送门: 《linux专栏》《嵌入式linux驱动开发》《linux系统移植专栏》 ❄专栏传送门: 《freertos专栏》《STM32 HAL库专栏》 ⭐️流水不争先,争的是滔滔不绝  📚博主简介:第二十届中国研究生电子设计竞赛全国二等奖 |国家奖学金 | 省级三好学生 | 省级优秀毕业生获得者 | ZEEKLOG新星杯TOP18 | 半导纵横专栏博主 | 211在读研究生 在这里主要分享自己学习的linux嵌入式领域知识;有分享错误或者不足的地方欢迎大佬指导,也欢迎各位大佬互相三连 目录 前言  一、实验基础说明 1.1、互斥体简介 1.2 本次实验设计思路 二、硬件原理分析(看过之前博客的可以忽略) 三、实验程序编写 3.1 互斥体 LED 驱动代码(mutex.c) 3.2.1、设备结构体定义(28-39

By Ne0inhk
Flutter for OpenHarmony:swagger_dart_code_generator 接口代码自动化生成的救星(OpenAPI/Swagger) 深度解析与鸿蒙适配指南

Flutter for OpenHarmony:swagger_dart_code_generator 接口代码自动化生成的救星(OpenAPI/Swagger) 深度解析与鸿蒙适配指南

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 后端工程师扔给你一个 Swagger (OpenAPI) 文档地址,你会怎么做? 1. 对着文档,手写 Dart Model 类(容易写错字段类型)。 2. 手写 Retrofit/Dio 的 API 接口定义(容易拼错 URL)。 3. 当后端修改了字段名,你对着报错修半天。 这是重复劳动的地狱。 swagger_dart_code_generator 可以将 Swagger (JSON/YAML) 文件直接转换为高质量的 Dart 代码,包括: * Model 类:支持 json_serializable,带 fromJson/

By Ne0inhk
Linux 开发别再卡壳!makefile/git/gdb 全流程实操 + 作业解析,新手看完直接用----《Hello Linux!》(5)

Linux 开发别再卡壳!makefile/git/gdb 全流程实操 + 作业解析,新手看完直接用----《Hello Linux!》(5)

文章目录 * 前言 * make/makefile * 文件的三个时间 * Linux第一个小程序-进度条 * 回车和换行 * 缓冲区 * 程序的代码展示 * git指令 * 关于gitee * Linux调试器-gdb使用 * 作业部分 前言 做 Linux 开发时,你是不是也遇到过这些 “卡脖子” 时刻?写 makefile 时,明明语法没错却报错,最后发现是依赖方法行没加 Tab;想提交代码到 gitee,记不清 git add/commit/push 的 “三板斧”,还得反复搜教程;用 gdb 调试程序,输了命令没反应,才想起编译时没加-g生成 debug 版本;甚至连写个进度条,都搞不懂\r和\n的区别,导致进度条乱跳…… 其实这些问题,

By Ne0inhk