搜索与图论第六期 最短路问题


前言

最短路问题真的很重要很重要希望大家都能够完全掌握所有最短路算法!!

一、最短路问题的分类

Dijkstra:


Dijkstra算法是一种著名的图算法,主要用于求解有权图中的单源最短路径问题。它由荷兰计算机科学家艾兹赫尔·戴克斯特拉(Edsger Wybe Dijkstra)在1956年首次提出。Dijkstra算法的核心思想是通过以下步骤逐步构建最短路径树:

初始化:创建一个空白的最短路径字典,其中每个节点的距离设置为无穷大,起始节点的距离设置为0。
标记已访问节点:创建一个已访问节点集合,并将所有节点都加入这个集合。
更新距离:对于未被访问的节点,从其未被访问的邻居中选择距离当前节点最近的邻居,将其标记为已访问,并且更新该邻居节点的距离。
重复上述步骤:直到所有节点都被访问,此时已经得到了从起始节点到所有其他节点的最短路径。
Dijkstra算法的特点在于它能够处理图中的负权边,但通常会忽略这些边,因为它们不会影响最终的路径长度计算。如果图中存在负权边,可能需要使用其他的图算法,如Bellman-Ford算法。此外,Dijkstra算法的时间复杂度通常是O(V^2),其中V是节点数量,但如果使用优先队列来优化,时间复杂度可以减少到O(Elog(V)),其中E是边数。1

在实际编程实现时,可以使用不同的数据结构和算法来实现Dijkstra算法,以提高效率。例如,可以使用优先队列或堆来加速松弛操作,从而减少总体时间复杂度。2

总结一下,Dijkstra算法的主要优点是可以有效地解决单源最短路径问题,并且在大多数情况下不需要考虑负权边的影响。它在多个领域有着广泛的应用,包括路线规划、网络路由、资源分配等。

Bellman-Ford算法:

贝尔曼-福特算法(Bellman-Ford Algorithm)是一种用于求解单源最短路径问题的算法,由理查德·贝尔曼(Richard Bellman)和莱斯特·福特(Lester Ford)共同创立。该算法能够处理图中的负权边,并具有简单的实现方式和较高的时间复杂度。贝尔曼-福特算法的核心思想是通过多次松弛操作来确定所有可能的最短路径。每次迭代中,算法会更新所有节点的距离,确保它们符合“三角不等式”,即任意两点间的距离加上第三者的重量小于或等于这两点间距离之和。

尽管贝尔曼-福特算法在处理带负权边的最短路径问题上表现良好,但在某些情况下可能会遇到困难,如当图中存在负权环路时,可能会导致无法找到任何有效的最短路径。此外,虽然它可以处理负权边,但其时间复杂度为 \( O(VE) \),其中 \( V \) 是顶点的数量,\( E \) 是边的数量,这使得它在实践中可能不是最佳选择。

总结来说,贝尔曼-福特算法的主要优点包括支持负权边和简单性,而其主要缺点在于高的时间复杂度。为了提高效率,算法可以进行一些优化措施。需要注意的是,贝尔曼-福特算法有时也被称作 Moore-Bellman-Ford 算法,因为它还涉及到了另一位科学家 Edward F. Moore 的贡献。

SPFA算法:

SPFA算法
SPFA 算法是 Bellman-Ford算法 的队列优化算法的别称,通常用于求含负权边的单源最短路径,以及判负权环

Floyd算法:

floyd算法
Floyd算法,也被称为弗洛伊德算法或插点法,是一种解决加权图中顶点间最短路径问题的算法。它可以处理有向图或负权图(但不能存在负权回路),并同时用于计算有向图的传递闭包。Floyd算法的名称来源于其创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德。

Floyd算法的核心思想是利用动态规划技术来构建一个路径矩阵,这个矩阵包含了图中所有顶点对之间的最短路径长度。算法的基本步骤包括初始化路径矩阵、进行多次更新操作以及最终获取任意两点之间的最短路径。

具体来说,算法会创建两个矩阵:一个存储了顶点对之间的距离,另一个存储了这些距离的逆。在每一次迭代中,都会根据已有的信息更新这两个矩阵。这个过程涉及到多个嵌套的for循环,直到所有的路径都被计算出来为止。

Floyd算法的时间复杂度和空间复杂度分别为O(n^3)和O(n^2),这意味着它在处理大规模网络图时会比较耗时。此外,虽然算法本身不需要回溯路径的具体信息,但它确实可以用来构造出最短路径的详细列表。

总结一下,Floyd算法的主要特点和应用场景如下:

适用范围:适用于有向图或负权图,不能有负权回路。
时间复杂度:O(n^3),即n³次操作。
空间复杂度:O(n^2),即n²个变量。
主要用途:求解任意两点间的最短路径,也可以用于计算传递闭包。
其他应用:在某些情况下,可以用于查找关系的传递闭包。

二、例题

1.朴素Dijkstra:


AC代码:

#include<bits/stdc++.h>using namespace std;const int N = 510;
int g[N][N];
int dis[N];
bool st[N];
int n,m;
int dij()
{memset(dis,0x3f,sizeof dis);dis[1] = 0;for(int i=0;i<n;i++){int t = -1;for(int j=1;j<=n;j++){if(!st[j] && (t==-1 || dis[t]>dis[j]))t=j;}st[t] = true;for(int j=1;j <= n;j++){dis[j] = min(dis[t]+g[t][j],dis[j]);}}if(dis[n] == 0x3f3f3f3f) return -1;return dis[n];
}
int main()
{cin>>n>>m;memset(g,0x3f,sizeof g);while(m--){int a,b,c;scanf("%d%d%d",&a,&b,&c);g[a][b] = min(g[a][b],c);}int t = dij();cout<<t<<endl;return 0;
}

2、堆优化Dijkstra:

AC代码:

#include<bits/stdc++.h>using namespace std;const int N = 15e4+10; 
typedef pair<int ,int>PII;
int h[N],e[N],ne[N],idx,w[N];
int n,m;
int dis[N],st[N];
void add(int a,int b,int c)
{e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx ++;
}int dij()
{memset(dis,0x3f,sizeof dis);dis[1] = 0;priority_queue<PII,vector<PII>,greater<PII>>heap;heap.push({0,1});//距离加顶点;while(heap.size()){auto t = heap.top();heap.pop();int ver = t.second,distance = t.first;if(st[ver]) continue;st[ver] = true;for(int i=h[ver];i!=-1;i= ne[i]){int j = e[i];//为了更新其他的边if(dis[j] > w[i] + dis[ver] && !st[j]){dis[j]  =w[i]+ dis[ver];heap.push({dis[j],j});}}}if(dis[n] == 0x3f3f3f3f ) return -1;return dis[n];
}
int main()
{cin>>n>>m;memset(h,-1,sizeof h);while(m--){int a,b,c;cin>>a>>b>>c;add(a,b,c);}cout<<dij()<<endl;return 0;
}

3、 有边数限制的最短路:

AC代码:

#include<bits/stdc++.h>using namespace std;const int N = 520,M = 10010;
int n,m,k;
int dis[N],backup[M];struct Edge
{int a,b,w;
}edges[M];int bellman_ford()
{memset(dis,0x3f,sizeof dis);dis[1] = 0;for(int i = 0; i < k; i ++){memcpy(backup,dis,sizeof dis);for(int j=0;j< m;j ++){int a = edges[j].a,b=edges[j].b,w=edges[j].w;dis[b] = min(dis[b],backup[a] + w);}}if(dis[n] > 0x3f3f3f3f/2 ) return -1;return dis[n];
}
int main()
{cin>>n>>m>>k;for(int i=0;i<m;i++){int a,b,w;scanf("%d%d%d",&a,&b,&w);edges[i] = {a,b,w};}int t = bellman_ford();if(t == -1) puts("impossible");else printf("%d\n",t);return 0;
}

4、spfa判断负环:

AC代码:

#include<bits/stdc++.h>using namespace std;const int N = 15e4+10; 
typedef pair<int ,int>PII;
int h[N],e[N],ne[N],idx,w[N];
int n,m;
int dis[N],st[N],cnt[N];
void add(int a,int b,int c)
{e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx ++;
}int spfa()
{dis[1] = 0;queue<int>q;for(int i=1;i<=n;i++){st[i]= true;q.push(i);}while(q.size()){int t = q.front();q.pop();st[t]  = false;for(int i=h[t];i!=-1;i = ne[i]){int j= e[i];if(dis[j] > dis[t] + w[i]){dis[j] = dis[t]+w[i];cnt[j] = cnt[t] + 1;if(cnt[j]>=n) return true; q.push(j);st[j] = true;}}}return false;
}
int main()
{cin>>n>>m;memset(h,-1,sizeof h);while(m--){int a,b,c;cin>>a>>b>>c;add(a,b,c);}if(spfa()) puts("Yes");else puts("No");return 0;
}

5、spfa求最短路:

AC代码:

#include<bits/stdc++.h>using namespace std;const int N = 15e4+10; 
typedef pair<int ,int>PII;
int h[N],e[N],ne[N],idx,w[N];
int n,m;
int dis[N],st[N];
void add(int a,int b,int c)
{e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx ++;
}int dij()
{memset(dis,0x3f,sizeof dis);dis[1] = 0;queue<int>q;q.push(1);st[1] = true;while(q.size()){int t = q.front();q.pop();st[t]  = false;for(int i=h[t];i!=-1;i = ne[i]){int j= e[i];if(dis[j] > dis[t] + w[i]){dis[j] = dis[t]+w[i];q.push(j);st[j] = true;}}}if(dis[n] == 0x3f3f3f3f) return -1;return dis[n];
}
int main()
{cin>>n>>m;memset(h,-1,sizeof h);while(m--){int a,b,c;cin>>a>>b>>c;add(a,b,c);}int t = dij();if(t == -1) puts("impossible");else cout<<t<<endl;return 0;
}

6、Floyd求最短路:

AC代码:

#include<bits/stdc++.h>using namespace std;const int N = 210,INF= 1e9;int n,m,q;
int d[N][N];
int main()
{cin>>n>>m>>q;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(i == j) d[i][j] == 0;else d[i][j] = INF;}}while(m--){int a,b,w;scanf("%d%d%d",&a,&b,&w);d[a][b] = min(d[a][b],w);}for(int k=1;k<=n;k++){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){d[i][j] = min(d[i][j],d[i][k]+d[k][j]);}}}while(q--){int a,b;scanf("%d%d",&a,&b);if(d[a][b]>INF/2) puts("impossible");else printf("%d\n",d[a][b]);}return 0;
}

总结:这部分真的特别特别的重要,希望大家能够完全掌握,对以后的面试也有帮助的,感谢大家的观看!!!

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

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

相关文章

vue2(Vuex)、vue3(Pinia)、react(Redux)状态管理

vue2状态管理Vuex Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它使用集中式存储管理应用的所有组件的状态&#xff0c;以及规则保证状态只能按照规定的方式进行修改。 State&#xff08;状态&#xff09;:Vuex 使用单一状态树&#xff0c;即一个对象包含全部的应用层…

线性代数的学习和整理23:用EXCEL和python 计算向量/矩阵的:内积/点积,外积/叉积

目录 1 乘法 1.1 标量乘法(中小学乘法) 1.1.1 乘法的定义 1.1.2 乘法符合的规律 1.2 向量乘法 1.2.1 向量&#xff1a;有方向和大小的对象 1.2.2 向量的标量乘法 1.2.3 常见的向量乘法及结果 1.2.4 向量的其他乘法及结果 1.2.5 向量的模长&#xff08;长度&#xff0…

【极数系列】Flink环境搭建(02)

【极数系列】Flink环境搭建&#xff08;02&#xff09; 引言 1.linux 直接在linux上使用jdk11flink1.18.0版本部署 2.docker 使用容器部署比较方便&#xff0c;一键启动停止&#xff0c;方便参数调整 3.windows 搭建Flink 1.18.0版本需要使用Cygwin或wsl工具模拟unix环境…

RAMROM

RAM&#xff08;Random Access Memory&#xff09;&#xff0c;随机存取存储器&#xff0c;也叫主存&#xff0c;又称内存&#xff08;动态ROM&#xff09;&#xff0c;是与CPU直接交换数据的内部存储器。它可以随时读写&#xff08;刷新时除外&#xff09;&#xff0c;而且速度…

Flutter 自定义AppBar实现滚动渐变

1、使用ListView实现上下滚动。 2、使用Stack&#xff1a;允许将其子部件放在彼此的顶部&#xff0c;第一个子部件将放置在底部。所以AppBar&#xff0c;写在ListView下面。 3、MediaQuery.removePadding&#xff1a;当使用ListView的时候发现&#xff0c;顶部有块默认的Padd…

服务器数据恢复—服务器进水导致阵列中磁盘同时掉线的数据恢复案例

服务器数据恢复环境&#xff1a; 数台服务器数台存储阵列柜&#xff0c;共上百块硬盘&#xff0c;划分了数十组lun。 服务器故障&检测&#xff1a; 外部因素导致服务器进水&#xff0c;进水服务器中一组阵列内的所有硬盘同时掉线。 北亚数据恢复工程师到达现场后发现机房内…

链路聚合原理与配置

链路聚合原理 随着网络规模不断扩大&#xff0c;用户对骨干链路的带宽和可靠性提出了越来越高的要求。在传统技术中&#xff0c;常用更换高速率的接口板或更换支持高速率接口板的设备的方式来增加带宽&#xff0c;但这种方案需要付出高额的费用&#xff0c;而且不够灵活。采用…

【GitHub项目推荐--一个语音机器人项目】【转载】

推荐一个腾讯大佬开源的语音对话机器人&#xff1a;wukong-robot &#xff0c;悟空机器人在 GitHub 上斩获 3.2K 的 Star。 这是一个简单灵活的中文语音对话机器人项目&#xff0c;目的是让中国的开发者也能快速打造个性化的智能音箱&#xff0c;同时&#xff0c;该项目还是第…

JMeter 设置请求头信息的详细步骤

在使用 JMeter 的过程中&#xff0c;我们会遇到需要设置请求头信息的场景。比如&#xff1a; POST 传过去的 Body 数据是 json 格式的。需要填添加头信息&#xff1a;Content-Type&#xff1a;application/json。在 header 中用 token 来传用户的认证信息。 下面&#xff0c;…

编程语言MoonBit新增矩阵函数的语法糖

MoonBit更新 1. 新增矩阵函数的语法糖 新增矩阵函数的语法糖&#xff0c;用于方便地定义局部函数和具有模式匹配的匿名函数&#xff1a; fn init {fn boolean_or { // 带有模式匹配的局部函数true, _ > true_, true > true_, _ > false}fn apply(f, x) {f(x)}le…

【Qt Quick 项目(第一集Qt Quick UI 项目项目创建)】

# Qt Quick 项目 到底什么是Qt Qml、什么是Qt Quick、QtQuick应用程序与Qt Widget程序有何区别,为了让读者在学习QML之前有一个整体认识,这里先介绍几个Quick项目。 01 Qt Quick UI 项目

【江科大】STM32:(超级详细)定时器输出比较

文章目录 输出比较单元特点 高级定时器&#xff1a;均有4个通道 PWM简介PWM&#xff08;Pulse Width Modulation&#xff09;脉冲宽度调制输出比较通道PWM基本结构基本定时器 参数计算捕获/比较通道的输出部分详细介绍如下&#xff1a; 舵机介绍硬件电路 直流电机介绍&#xff…

CRM的定义、功能,以及国内外CRM系统排名

什么是客户关系管理? CRM是(客户关系管理)的缩写&#xff0c;是一个管理与客户关系的系统。CRM的主要功能是管理基本客户信息和购买历史的客户管理、分析潜在客户和新客户的客户分析、对询问的自动回复的响应以及通过电子邮件通讯和研讨会吸引客户。它是加强和维护与客户和潜…

proxy 代理的接口报错301问题

项目系统里仅仅这个接口报错&#xff0c;反向代理错误导致。 默认情况下&#xff0c;不接受运行在HTTPS上&#xff0c;且使用了无效证书的后端服务器。如果你想要接受&#xff0c;修改配置&#xff1a;secure: false&#xff08;简单意思&#xff1a;如果本地没有进行过https相…

算法第二十二天-最大数

最大数 题目要求 解题思路 今天的题目&#xff0c;让我们将一组数字重新组合&#xff0c;构成一个最大的整数。由于构成的整数非常大&#xff0c;所以返回结果需要字符串格式。 分析一下规律&#xff1a; 为了避免用int型或者long型越界&#xff0c;所以我们需要把数字先转换…

用ChatGPT教学、科研!大学与OpenAI合作

亚利桑那州立大学&#xff08;简称“ASU”&#xff09;在官网宣布与OpenAI达成技术合作。从2024年2月份开始&#xff0c;为所有学生提供ChatGPT企业版访问权限&#xff0c;主要用于学习、课程作业和学术研究等。 为了帮助学生更好地学习ChatGPT和大语言模型产品&#xff0c;AS…

计算机视觉工程师就业前景如何?

计算机视觉作为一门快速发展的技术领域&#xff0c;其就业前景非常广阔。以下是对计算机视觉就业前景的分析&#xff1a; 市场规模&#xff1a;计算机视觉行业的市场规模正在持续扩大。根据行业分析报告&#xff0c;预计全球计算机视觉市场规模将在2025年达到530亿美元&#xf…

C#,入门教程(35)——哈希表(Hashtable)的基础知识与用法

上一篇&#xff1a; C#&#xff0c;入门教程(34)——关于函数的参数之引用&#xff08;ref&#xff09;的一点知识与源程序https://blog.csdn.net/beijinghorn/article/details/125411351 有一段故事&#xff1a; King Log The frogs in the lake had an easy life doing ex…

k8s-helm

Helm: 什么是helm,在没有这个heml之前&#xff0c;deployment service ingress的作用就是通过打包的方式&#xff0c;把deployment service ingress这些打包在一块&#xff0c;一键式的部署服务&#xff0c;类似于yum 官方提供的一个类似于安全仓库的功能&#xff0c;可以实现…

linux docker-compose安装失败解决

1.去github下载到本地 https://github.com/docker/compose/releases/ 2.上传到linux 服务器 mv dokcer-compose-linux-x86_64 /usr/loacal/bin/docker-compose 3.给权限 chmod x /usr/local/bin/docker-compose 4.查看是否安装成功 docker-compose -version 5.卸载 …