【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

[安卓] Kotlin中的架构演进:从MVC到MVVM

从Java到Kotlin,不仅仅是语法的升级,更是架构思维的进化。本文将带你全面掌握Kotlin在Android开发中三种核心架构模式:MVC、MVP、MVVM,揭示如何用Kotlin特性写出更优雅的架构代码。 引言:为什么Android开发者需要架构模式? 如果你有过Java Android开发经验,一定遇到过这些问题:Activity/Fragment代码臃肿(动辄上千行)、业务逻辑与UI逻辑混杂、测试困难、代码难以维护。架构模式正是为了解决这些问题而生的。而Kotlin,以其简洁的语法和强大的特性,让这些架构模式的实现变得更加优雅。 让我们从一个真实案例开始——用户登录模块,看看在不同架构模式下的演变: // 糟糕的无架构代码(Java风格)class BadLoginActivity :AppCompatActivity(){privatelateinitvar editUsername: EditText privatelateinitvar editPassword: EditText privatelateinitvar buttonLogin: Button

By Ne0inhk
【Kafka进阶篇】深入Kafka内部:日志存储的设计思路,藏着中间件高性能的真相

【Kafka进阶篇】深入Kafka内部:日志存储的设计思路,藏着中间件高性能的真相

🍃 予枫:个人主页 📚 个人专栏: 《Java 从入门到起飞》《读研码农的干货日常》 💻 Debug 这个世界,Return 更好的自己! 引言 做分布式开发的同学,几乎都用过Kafka,但多数人只停留在“生产者发消息、消费者收消息”的表层使用,很少深究:百万级消息并发下,Kafka如何快速定位目标消息?底层的.log、.index、.timeindex文件各司其职,又是如何配合实现高效读写的?今天就从物理层面拆解Kafka日志存储与索引机制,吃透这部分,不仅能搞定面试难点,更能在生产环境中精准优化Kafka性能。 文章目录 * 引言 * 一、前言:为什么要搞懂Kafka日志与索引机制? * 二、核心前提:Kafka日志的“分段存储”设计 * 三、深度拆解:三种核心文件的作用与结构 * 3.1 .log文件:消息的“真正存储载体” * 关键细节: * 3.2

By Ne0inhk

PostgreSQL:详解 PostGIS 地理信息数据处理

更多内容请见: 《深入掌握PostgreSQL数据库》 - 专栏介绍和目录 文章目录 * 一、PostGIS 简介 * 1.1 什么是 PostGIS? * 1.2 PostGIS 能做什么? * 二、安装与启用 PostGIS * 2.1 安装方式(以 Ubuntu 为例) * 2.2 验证安装 * 三、核心数据类型 * 3.1 geometry(几何类型) * 3.2 geography(地理类型) * 3.3 常见几何子类型(OGC 标准) * 四、空间数据表示与输入 * 4.1 WKT(Well-Known Text)

By Ne0inhk
Flutter 组件 fam 适配鸿蒙 HarmonyOS 实战:文件资产监控,构建分布式媒体管理与全场景资源分发治理架构

Flutter 组件 fam 适配鸿蒙 HarmonyOS 实战:文件资产监控,构建分布式媒体管理与全场景资源分发治理架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 fam 适配鸿蒙 HarmonyOS 实战:文件资产监控,构建分布式媒体管理与全场景资源分发治理架构 前言 在鸿蒙(OpenHarmony)生态迈向万物智联、涉及海量分布式文件同步、社交应用图片即时刷新及严苛的沙箱存储审计背景下,如何实现一套既能覆盖系统级文件变动感知、又能保障低功耗运行且具备“亚秒级”事件回调能力的“文件监控中心”,已成为决定应用数据发现速率与存储交互稳健性的基石。在鸿蒙设备这类强调分布式文件系统(HMDFS)协同且存储分区高度隔离的场景下,如果应用依然采用低效的定时轮询扫描,由于由于 I/O 资源的无效损耗,极易由于由于“电量泄露”导致鸿蒙应用在后台由于由于由于由于后台任务限制而被系统强制挂起。 我们需要一种能够解耦物理路径、支持递归监听且符合鸿蒙事件驱动模型的文件监控方案。 fam(File Asset Monitor)为 Flutter 开发者引入了“存储感知”范式。它不是简单的 File 操作扩展,

By Ne0inhk