图论---最短路径问题

        解决图论问题中的最短路径问题一般有四种算法,分别是Floyd算法、Dijkstra算法、Bellman-Ford算法和SPFA算法,下面介绍一下这几种算法的模板和原理用途。

Floyd算法

原理:Floyd本质上是一个动态规划的思想,每一次循环更新经过前k个节点,i到j的最短路径

用途:Floyd算法是求解多源最短路时通常选用的算法,经过一次算法即可求出任意两点之间的最短距离,并且可以处理有负权边的情况(但无法处理负权环)。时间复杂度为O(n3)。

代码框架:

#define N 100
const int INF = 0x3f3f3f3f;
int d[N][N];
// 代码初始化,共有n个顶点
for(int i = 0; i < n; i++){for(int j = 0; j < n; j++){d[i][j] = i == j ? 0 : INF;}
}
// 将每条边的值加入到dis中去,这里不再赘叙
// Floyd算法
for(int k = 0; k < n; k++){for(int i = 0; i < n; i++){for(int j = 0; j < n; j++){d[i][j] = min(d[i][j], d[i][k] + d[k][j]);}}
}

Dijkstra算法

原理:将结点分成两个集合:已确定最短路长度的点集(记为S集合)的和未确定最短路长度的点集(记为T集合)。一开始所有的点都属于T集合。

初始化dis(S) = 0,其他点的S均为INT_MAX。

然后重复这些操作:

  1. 从T集合中,选取一个最短路长度最小的结点,移到S集合中。

  2. 对那些刚刚被加入S集合的结点p的所有出边执行松弛操作。松弛操作即更新dis(T)的值,具体公式为:dis(T) = min(dis(T), dis(p) + w(p)(T))。

直到T集合为空,算法结束。

用途:基于贪心思想的一种求解 非负权图单源最短路径的算法。暴力的话O(n * n)。

代码框架:

// 假设共有n个节点
#define N 100
vector<vector<int>> w; // 储存每条边的权重
int dis[N]; // 储存开始节点到其他节点的最短距离
bool s[N]; // 储存已找到最短路径的节点
int dijkstra(int x, int des){ // 假设x节点为开始节点,des目的节点// 初始化dismemset(dis, 0x3f, sizeof(dis));dis[x] = 0;for(int i = 0; i < n; i++){int p = -1; // 本次循环加入到S集合的节点for(int j = 0; j < n; j++){ // 在集合T中寻找距离最小的节点if(!s[j] && (p == -1 || dis[p] > dis[j])){t = j;}}//用p更新其他节点到开始节点x的最短距离for(int j = 0; j < n; j++){dis[j] = minx(dis[j], dis[p] + w[p][j]);}s[p] = true;}return dis[des];
}

Bellman-Ford算法

原理:逐基于动态规划,遍的对图中每一个边去迭代计算起始点到其余各点的最短路径(松弛操作),执行n - 1遍,最终得到起始点到其余各点的最短路径。

用途:Bellman–Ford 算法是一种基于松弛(relax)操作的单源最短路算法,可以处理负权边与负权回路。对于一个不包含负权环的V个点的图,任意两点之间的最短路径至多包含V-1条边。如果存在负权环,每次在负权环上走一圈都会使环上的每一个点的距离减少,因此不存在最短路径。时间复杂度为O(nm),其中n为节点个数,m为边数。

可以解决边数限制的最短路径问题,SPFA无法代替。

代码框架:

// 假设共有n个节点,m条边
struct Edge { // 边u表示出点,v表示入点,w表示边的权重 int u, v, w; 
}edges[m];
int dis[100]; // 储存开始节点到其他节点的最短距离
​
int Bellman_Ford(int start, int des){ // 开始节点为start,结束节点为desmemset(dis, 0x3f, sizeof(dis));dis[start] = 0;for(int i = 0; i < n; i++){ // 迭代n 次for(int j = 0; j < m; j++){if(i == n - 1 && dis[edges[i].v] > dis[edges[i].u] + edges[i].w){// 判断是否出现负权回路// 最短距离发生更新,说明存在负权回路,返回-1return -1;}dis[edges[j].v] = min(dis[edges[j].v], dis[edges[j].u] + edges[j].w);}}return dis[des] > 0x3f3f3f3f / 2 ? -1 : dis[des];
}

SPFA算法

原理:初始时将起点加入队列。每次从队列中取出一个元素,并对所有与它相邻的点进行修改,若某个相邻的点修改成功,则将其入队。直到队列为空时算法结束。算法的流程为:

  1. 将除源点之外的所有的点当前距离初始化为无穷,并标记为未入队。源点的当前距离为0,将源点入队。

  2. 取出队首u,遍历u的所有出边,检查是否能更新所连接的点v的当前距离。如果v的当前距离被更新并且v不在队中,则将v入队。重复该操作直到队列为空。

  3. 检查是否存在负权环的方法为:记录一个点的入队次数,如果超过n-1次说明存在负权环,因为最短路径上除自身外至多n-1个点,故一个点不可能被更新超过n-1次。

用途:SPFA是队列优化的Bellman-Ford算法,因此用途与Bellman-Ford算法用途相同,但是时间复杂度更低。平均复杂度O(m),最坏复杂度O(n * m)。

代码框架:

// 假设共有n个节点,m条边
#define N 100
struct Edge { // v表示出边,w表示边的权重 int v, w; 
};
vector<Edge> e[n]; // 与各个节点相连的边
int dis[N]; // 储存开始节点到其他节点的最短距离
bool s[N]; // 判断节点是否在队列中
int cnt[N]; // 记录边数
int spfa(int start, int des){ // 开始节点为start,结束节点为desmemset(dis, 0x3f, sizeof(dis));dis[start] = 0;queue<int> q;q.push(start);s[start] = true;while(!q.empty()){int u = q.front();q.pop();s[u] = false;for(auto &ed : e[u]){ // 遍历节点p能直接到达的节点,松弛操作int v = ed.v, w = ed.w;if(dis[v] > dis[u] + w){dis[v] = dis[u] + w;cnt[v] = cnt[u] + 1;if(cnt[v] >= n){ // 出现负权回路return -1;}if(!s[v]){q.push(v);s[v] = true;}}}}return dis[des] > 0x3f3f3f3f / 2 ? -1 : dis[des];
}

总结

(1)单源最短路:给定V中的一个顶点,称为源。要计算从源到其他所有各顶点的最短路径长度。这里的长度就是指路上各边权之和。这个问题通常称为单源最短路径 问题。

所有边权都是正数:

朴素Dijkstra算法 O(n^2) 适合稠密图,贪心思想

堆优化版的Dijkstra算法 O(mlogn)适合稀疏图,贪心思想

存在负权边:

Bellman-ford O(nm),动态规划思想

SPFA 一般:O(m),最坏O(nm)

(2)多源汇最短路:任意两点最短路径被称为多源最短路径,即给定任意两个点,一个出发点,一个到达点,求这两个点的之间的最短路径,就是任意两点最短路径问题:Floyd算法 O(n^3)

题单

743. 网络延迟时间 - 力扣(LeetCode)

787. K 站中转内最便宜的航班 - 力扣(LeetCode)

1928. 规定时间内到达终点的最小花费 - 力扣(LeetCode)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/98055.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

你的librosa和scikit-learn打架了吗?

被这个问题困扰好久&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 我的原来版本librosa0.7.1 和 scikit-learn1.3.1 一直拆了按&#xff0c;按…

TypeScript应用

目录 TypeScript应用defineProps的TS写法defineEmits的TS写法ref的TS写法1.简单数据类型2.复杂数据类型 reactive的TS写法1.默认值属性是固定的2.根据默认值推导不出我们需要的类型 computed和TS事件处理与TSTemplate Ref与TS非空断言TypeScript类型声明文件TS类型声明文件是什…

【UE5 Cesium】15-Cesium for Unreal 加载本地影像和地形

目录 一、加载全球无高度地形 二、加载区域DEM 三、加载离线地图影像 一、加载全球无高度地形 1. 先去如下网址下载全球无高度地形&#xff1a;Using a global terrain layer without height detail - #9 by RidhwanAziz - Cesium for Unreal - Cesium Community 下载后如下…

好物周刊#12:计算机考研资料

https://cunyu1943.github.io https://yuque.com/cunyu1943 村雨遥的好物周刊&#xff0c;记录每周看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;每周五发布。 一、项目 1. JEECG BOOT 低代码开发平台 一款基于代码生成器的低代码开发平台&#xff01;前后…

scala数组函数合集

目录 1. 添加类函数 2.生成类函数 3.删除类函数 4.查找类函数 5.统计类函数 6.修改类函数 7.判断类函数 8.获取集合元素 9.集合操作类函数 10.转换类函数 11.工具类函数 12.集合内与集合间计算函数 在 scala 中Array数组是一种可变的、可索引的数据集合 创建数组…

FFmpeg合并多个音频并解决声音变小的方法

在制作或编辑视频时,音频是一个重要的组成部分。但是当尝试使用FFmpeg在MP4视频中插入多个音频时,可能会遇到声音变小的问题。 本文将详细解释这一现象的原因,并提供代码示例来解决这一问题。 文章目录 多个音频插入MP4声音变小原因Python合并音频和解决办法FFmepg合并音频…

优秀程序员是怎么思考的?

首发日更公 Z 号&#xff1a;十二又十三 作为一名优秀的程序员&#xff0c;思考是我们工作中最重要的一部分。它不仅能够帮助我们解决问题&#xff0c;还能够提升我们的技术水平和职业发展。那么&#xff0c;优秀程序员是如何思考的呢&#xff1f;本文将为您介绍一个思考框架和…

想升级macOS Big Sur,但是MacBook内存空间不够该怎么办?

随着使用时间的增长&#xff0c;我们会发现Mac电脑的存储空间越来越少&#xff0c;这时候我们就需要对Mac电脑进行清理&#xff0c;以释放更多的存储空间。那么&#xff0c;Mac空间不足怎么解决呢&#xff1f; 1.清理垃圾文件 Mac空间不足怎么解决&#xff1f;首先要做的就是清…

Linux: 基础IO

学习目标 1.C接口与系统调用接口的差别 2.文件描述符, 重定向, 一切皆文件, 缓冲区 3.fd与FILE, 系统调用和库函数的关系 4.系统中的inode 5.软硬链接 6.动静态库 预备知识 1.文件 内容 属性 2.文件的所有操作: a. 对内容的操作 b.对属性的操作 3.文件在磁盘(硬件)上, 我…

前端—— 分层模型和应用协议

1 分层模型 MAC地址 可以认为计算机专属&#xff0c;可以认为每台计算机的 MAC地址 固定不变&#xff1b; IP地址 可以认为是计算机当前的【家庭地址】&#xff0c;动态唯一&#xff0c;家庭地址变化&#xff0c;IP地址 也跟着变化&#xff1b; 举个例子&#xff0c;A 给 B 发…

MyBatisPlus(十五)分页查询

说明 MyBatisPlus 提供了分页查询的功能。 MyBatisPlus 的分页功能&#xff0c;是通过分页插件实现的。要使用分页功能&#xff0c;需要配置分页插件的拦截器。 MyBatisPlus 的分页功能&#xff0c;可以通过内置的API接口实现&#xff1b;也可以通过自定义的 mapper#method …

consulmanage使用

一、监控自建主机 需要在所有被监控的主机上部署node_exporter收集主机的监控数据 在此页面下载node_exporter安装包 Download | Prometheus 下载后解压安装包&#xff0c;并启动node_exporter服务 mkdir /opt/node_exporter && cd /opt/node_exporter tar -zxvf node_…

C/S架构学习之多线程实现TCP并发服务器

并发概念&#xff1a;并发是指两个或多个事件在同一时间间隔发生&#xff1b;多线程实现TCP并发服务器的实现流程&#xff1a;一、创建套接字&#xff08;socket函数&#xff09;&#xff1a;通信域选择IPV4网络协议、套接字类型选择流式&#xff1b; int sockfd socket(AF_IN…

【计算机视觉|人脸建模】学习从4D扫描中获取的面部形状和表情的模型

本系列博文为深度学习/计算机视觉论文笔记&#xff0c;转载请注明出处 标题&#xff1a;Learning a model of facial shape and expression from 4D scans 链接&#xff1a;Learning a model of facial shape and expression from 4D scans | ACM Transactions on Graphics Pe…

vue项目 ueditor使用示例

简介 UEditor是由百度Web前端研发部开发的所见即所得富文本web编辑器&#xff0c;具有轻量&#xff0c;功能丰富&#xff0c;易扩展等特点。UEditor支持常见的文本编辑功能&#xff0c;如字体、颜色、大小、加粗、斜体、下划线、删除线等&#xff0c;同时还支持超链接、图片上…

stm32的GPIO寄存器操作以及GPIO外部中断,串口中断

一、学习参考资料 &#xff08;1&#xff09;正点原子的寄存器源码。 &#xff08;2&#xff09;STM32F103最小系统板开发指南-寄存器版本_V1.1&#xff08;正点&#xff09; &#xff08;3&#xff09;STM32F103最小系统板开发指南-库函数版本_V1.1&#xff08;正点&a…

【数据结构】论如何拿捏快速排序?(含非递归)

目录 一&#xff0c;快速排序&#xff08;递归&#xff09; 1&#xff0c;快排思想 2&#xff0c;霍尔排序 3&#xff0c;挖坑法 4&#xff0c;前后指针法 5&#xff0c;快速排序优化 1&#xff0c;三数取中法选key 2&#xff0c;小区间优化 二&#xff0c;快速排序&a…

Decorator

Decorator 动机 在某些情况下我们可能会“过度地使用继承来扩展对象的功能”&#xff0c; 由于继承为类型引入的静态特质&#xff0c;使得这种扩展方式缺乏灵活性&#xff1b; 并且随着子类的增多&#xff08;扩展功能的增多&#xff09;&#xff0c;各种子类的组合&#xff…

typescript: Builder Pattern

/*** file: CarBuilderts.ts* TypeScript 实体类 Model* Builder Pattern* 生成器是一种创建型设计模式&#xff0c; 使你能够分步骤创建复杂对象。* https://stackoverflow.com/questions/12827266/get-and-set-in-typescript* https://github.com/Microsoft/TypeScript/wiki/…

用这些IDEA插件,让你早下班两小时

GenerateAllSetter:一键调用一个对象的所有setter方法 RestfulTool:自动显示所有URL接口&#xff0c;快速检索接口 SequenceDiagram:以图形界面形式显示方法调用链&#xff0c;方便阅读源码、梳理代码 CamelCase:变量下划线转驼峰命名 Rainbow Brackets:帮助程序员识别代码中括…