初识最短路径

一.最短路径的介绍

最短路径是图论和网络分析中一个重要的概念,它指的是在一个图或网络中连接两个节点或顶点的路径中,具有最小权重总和的路径。这个权重可以表示为路径上边或弧的长度、耗费、时间等,具体取决于问题的背景和应用场景。

如果你有学过最小生成树,你会发现,二者是有部分相同点的,都是在找权重和的最小值。

但是最小生成树找的是沟通所有节点的最小权重,而最短路径是找的是一个节点到另一个节点的最小权重。

因为从一个节点到另一个节点往往有多种路径,路径的长短也不同,我们的目的就是为了找到一个最短的路径,来达到省时省力的目的。

比如我们从A节点到E节点,分别有三条路径。

上路径:2(A->B)+4(B->E)=6

中路径:10(A->E)

下路径:4(A->C)+2(C->D)+6(D->E)=12

那么我们怎么使用代码找出最短路径呢?

用于解决最短路径可以使用Dijkstra 算法、SPFA算法、Floyd 算法等。

下面我们对这几种算法来介绍一下。

二.算法介绍

这里先给出一个例题,使用下面介绍成所有算法解决。

例题

输入数据:

4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4

1.Dijkstra 算法

Dijkstra 算法基于贪心策略,通过逐步找到从起点到所有其他节点的最短路径来工作。它适用于权重为非负的有向图和无向图。

算法的实现有以下几个步骤:

1.distances:距离数组,用于存储从起点到每个节点的最短距离估计值。初始时,将起点到自身的距离设置为0,其他节点的距离设置为无穷大。

2.visited:标记数组,用于标记节点是否已经被访问过。初始时,将所有节点标记为未访问。

3.previous:前驱数组,用于记录到达每个节点的最短路径中,当前节点的前一个节点是哪个。

4.从起点开始,将起点标记为当前节点,更新起点到相邻节点的距离,并将这些相邻节点加入候选集。

5.从候选集中选择距离最短的节点作为当前节点,并将其标记为已访问。

6.对于当前节点的每个相邻节点,如果经过当前节点到达该相邻节点的路径比起始点直接到达该节点的路径更短,则更新距离数组和前驱数组。

7.重复步骤3和步骤4,直到所有节点都被访问过或候选集为空。

8.最终得到起点到每个节点的最短路径长度和最短路径。

下面是实现例题的完整代码(含注释):

#include<bits/stdc++.h>
#define M 500010
#define inf 1234567890
using namespace std;
struct edge{int u,v,w,next;
}e[M];
struct node{int w,now;bool operator<(const node &k)const{return w>k.w;//堆优化,小的元素放在堆顶,大根堆 }
};
int head[M],re=0,n,m,s,v[M],dis[M];
priority_queue<node>q;
void add(int u,int v,int w)//链式前向星存图 
{e[++re].u=u;e[re].v=v;e[re].w=w;e[re].next=head[u];head[u]=re;
}
void dijkstra()
{for(int i=1;i<=n;i++) dis[i]=inf;//将点设置为无穷大 dis[s]=0;//起点设置为0 node p;p.w=0,p.now=s;q.push(p);while(!q.empty()){node k=q.top();q.pop();int u=k.now;if(v[u]) continue;//如果遍历过,直接跳过循环 v[u]=1;for(int i=head[u];i;i=e[i].next){//下一个点 int v=e[i].v;if(dis[v]>dis[u]+e[i].w)//更新最小权重 {dis[v]=dis[u]+e[i].w;q.push((node){dis[v],v});}		}}
}
int main()
{cin>>n>>m>>s;for(int i=0;i<m;i++){int u,v,w;cin>>u>>v>>w;//建边 add(u,v,w);}dijkstra();for(int i=1;i<=n;i++){cout<<dis[i]<<" ";}return 0;
}

我们来看运行结果:

也是成功AC。

2.SPFA算法

SPFA算法是一种用于解决单源最短路径问题的算法,是 Bellman-Ford 算法的一种优化版本。它通过队列实现松弛操作,以减少不必要的松弛次数,从而提高了算法的效率。

算法实现步骤:
1.distances:距离数组,用于存储从起点到每个节点的最短距离估计值。初始时,将起点到自身的距离设置为0,其他节点的距离设置为无穷大。

2.queue:队列,用于存储待处理的节点。初始时,将起点加入队列。

3.in_queue:标记数组,用于标记节点是否已经在队列中。初始时,将起点标记为在队列中。

4.从队列中取出一个节点作为当前节点,遍历该节点的所有相邻节点。

5.对于每个相邻节点,如果经过当前节点到达该相邻节点的路径比起始点直接到达该节点的路径更短,则更新距离数组,并将该相邻节点加入队列。

6.重复直到队列为空。

下面是实现例题的完整代码:

#include<bits/stdc++.h>
#define M 500010
#define inf 1234567890
using namespace std;
struct edge{int u,v,w,next;
}e[M];
int head[M],re=0,n,m,s,v[M],dis[M];
void add(int u,int v,int w)//链式前向星存图 
{e[++re].u=u;e[re].v=v;e[re].w=w;e[re].next=head[u];head[u]=re;
}
queue<int>q;//队列优化 
void SPFA()
{for(int i=1;i<=n;i++) dis[i]=inf;//将点设置为无穷大 dis[s]=0;//起点设置为0 q.push(s);while(!q.empty()){//直到所有节点全部入队,不会再有新的节点入队,慢慢出队至停止循环 int k=q.front();q.pop();v[k]=0;for(int i=head[k];i;i=e[i].next){//下一个点 int p=e[i].v;if(dis[p]>dis[k]+e[i].w)//更新最小权重 {dis[p]=dis[k]+e[i].w;if(!v[p])//如果不在队列里面,则入队 {v[p]=1;q.push(p);}}		}}
}
int main()
{cin>>n>>m>>s;for(int i=0;i<m;i++){int u,v,w;cin>>u>>v>>w;//建边 add(u,v,w);}SPFA();for(int i=1;i<=n;i++){cout<<dis[i]<<" ";}return 0;
}

下面是运行结果:

虽然运行结果正确,但是SPFA算法容易被卡数据,导致时间超限。

3.Floyd 算法

Floyd算法的时间复杂度为O(N^3),其中N是节点的数量。因此,对于大型图,Floyd算法可能会变得相对缓慢。然而,与其他单源最短路径算法不同,Floyd算法可以同时计算任意两个节点之间的最短路径,这在某些情况下可能是更方便的。

Floyd算法的核心是下面这个方程式,来自动态规划。

dp[j][k]=min(dp[j][k],dp[j][i]+dp[i][k]);

算法实现步骤:

  1. 初始化距离矩阵:将矩阵D初始化为图的邻接矩阵,如果两个节点之间有直接的边,则距离为边的权重;否则,距离为无穷大。同时,将对角线上的元素(即节点到自身的距离)初始化为0。

  2. 三重循环:对于每一对节点(i,j)作为可能的中间节点k,检查是否存在路径从节点i到节点j通过节点k的路径比直接从i到j的路径更短。如果是,则更新路径长度。

  3. 返回最终的距离矩阵D,其中D[i][j]表示从节点i到节点j的最短路径长度。

Floyd算法是这三种算法中最简单的,核心代码只有一点。

for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(i==j||dp[j][i]==inf) continue;for(int k=1;k<=n;k++){dp[j][k]=min(dp[j][k],dp[j][i]+dp[i][k]);} }}

下面是完整代码:

#include<bits/stdc++.h>
using namespace std;
#define M 10010
#define inf 1234567890
int n,m,s,dp[M][M];
void floyd()
{for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(i==j||dp[j][i]==inf) continue;//找存在边 for(int k=1;k<=n;k++){dp[j][k]=min(dp[j][k],dp[j][i]+dp[i][k]);//更新最小权重 } }}
}
int main()
{cin>>n>>m>>s;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)dp[i][j]=inf;//初始化矩阵 for(int i=1;i<=m;i++){int u,v,w;cin>>u>>v>>w;dp[u][v]=min(dp[u][v],w);//防止重边 }dp[s][s]=0;floyd();for(int i=1;i<=n;i++){cout<<dp[s][i]<<" ";}return 0;
}

下面是运行结果:

结果虽然正确,但是对于这题来说,运行速度太慢了。

所以在做题时,需要按照题目要求来选择合适算法。

三.总结

  1. Dijkstra算法:

    • 简介: Dijkstra算法是解决单源最短路径问题的一种贪心算法。它从起点开始,逐步找到从起点到所有其他节点的最短路径。
    • 运行速度: 在最坏情况下,Dijkstra算法的时间复杂度为O((V+E)logV),其中V是节点数,E是边数。在使用最小堆的实现中,它通常具有较好的性能。
  2. SPFA算法:

    • 简介: SPFA算法是Bellman-Ford算法的一种优化版本,通过使用队列来避免不必要的重复松弛操作,提高了效率。
    • 运行速度: SPFA算法的平均时间复杂度通常被认为是O(kE),其中k是一个常数。在实际应用中,它的性能通常比Bellman-Ford算法好,但对于存在负权回路的图,SPFA算法可能陷入死循环。
  3. Floyd算法:

    • 简介: Floyd算法是一种动态规划算法,用于解决图中所有节点对之间的最短路径问题。它通过迭代更新每一对节点之间的最短路径长度。
    • 运行速度: Floyd算法的时间复杂度为O(N^3),其中N是节点的数量。在大型图上可能变得相对缓慢,但与其他单源最短路径算法不同,Floyd算法可以同时计算任意两个节点之间的最短路径。

速度比较:

  • Dijkstra算法通常在稠密图上表现良好,特别是当使用最小堆等数据结构进行优化时。
  • Floyd算法的运行速度可能在大型图上较慢,但由于同时计算所有节点对之间的最短路径,它在某些情况下可能更方便。

总体而言,选择算法通常取决于图的规模、稀密度、边权重分布以及是否需要同时计算所有节点对之间的最短路径。


本篇完~

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

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

相关文章

【STM32 CubeMX】SPI层次结构SPI协议与SPI控制器结构

文章目录 前言一、SPI 程序层次1.1 硬件原理图1.2 硬件框图1.3 软件层次 二、SPI协议2.1 硬件连线2.2 如何访问SPI设备2.3 SPI 框图 总结 前言 随着嵌入式系统的迅猛发展&#xff0c;STM32系列微控制器在各种应用中得到广泛应用。在嵌入式系统设计中&#xff0c;串行外设接口&…

牛客网SQL进阶123:高难度试卷的得分的截断平均值

官网链接&#xff1a; SQL类别高难度试卷得分的截断平均值_牛客题霸_牛客网牛客的运营同学想要查看大家在SQL类别中高难度试卷的得分情况。 请你帮她从exam_。题目来自【牛客题霸】https://www.nowcoder.com/practice/a690f76a718242fd80757115d305be45?tpId240&tqId2180…

matplotlib从起点出发(13)_Tutorial_13_Autoscaling

0 自动放缩 轴上的限制可以手动设置&#xff08;例如ax.set_xlim(xmin, xmax))&#xff0c;或者Matplotlib可以根据Axes上已有的数据自动设置它们。此种放缩行为有许多选项&#xff0c;如下所述。 我们将从一个简单的折线图开始&#xff0c;显示自动缩放将轴限制扩展到数据的…

P1090 [NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G题解

题目 在一个果园里&#xff0c;多多已经将所有的果子打了下来&#xff0c;而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。 每一次合并&#xff0c;多多可以把两堆果子合并到一起&#xff0c;消耗的体力等于两堆果子的重量之和。可以看出&#xff0c;所…

绿色化 数据库 MongoDB 和 mysql 安装

绿色化 数据库 MongoDB 和 mysql 安装 【1.1】 前言 为什么要绿色化 安装呢&#xff1f;因为系统老升级&#xff0c;老重装&#xff01;&#xff01;也方便了解下数据库配置和库在那 绿色软件喜欢一般放在 D盘tools目录里 D:\tools\ 数据库 MongoDB D:\tools\MongoDB 数…

Mysql第二关之存储引擎

简介 所有关于Mysql数据库优化的介绍仿佛都有存储引擎的身影。本文介绍Mysql常用的有MyISAM存储引擎和Innodb存储引擎&#xff0c;还有常见的索引。 Mysql有两种常见的存储引擎&#xff0c;MyISAM和Innodb&#xff0c;它们各有优劣&#xff0c;经过多次优化和迭代&#xff0c;…

代码随想录算法训练营第十九天|654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树

654.最大二叉树 刷题https://leetcode.cn/problems/maximum-binary-tree/description/文章讲解https://programmercarl.com/0654.%E6%9C%80%E5%A4%A7%E4%BA%8C%E5%8F%89%E6%A0%91.html视频讲解https://www.bilibili.com/video/BV1MG411G7ox/?vd_sourceaf4853e80f89e28094a5fe…

软件工程师,OpenAI Sora驾到,快来围观

概述 近期&#xff0c;OpenAI在其官方网站上公布了Sora文生视频模型的详细信息&#xff0c;展示了其令人印象深刻的能力&#xff0c;包括根据文本输入快速生成长达一分钟的高清视频。Sora的强大之处在于其能够根据文本描述&#xff0c;生成长达60秒的视频&#xff0c;其中包含&…

1、若依(前后端分离)框架的使用

若依&#xff08;前后端分离&#xff09;框架的使用 0、环境1、下载若依(1) 下载并解压(2) 导入SQL语句(3) 配置Redis、MySQL 2、运行若依3、登录(1) 前端(2) 后端 4、获取用户角色、权限和动态路由(1) 获取用户角色、权限(2) 根据用户信息获取动态路由【getRouters】 5、杂6、…

阿里云服务器ECS租赁费用报价_CPU内存_带宽和系统盘价格表

2024年最新阿里云服务器租用费用优惠价格表&#xff0c;轻量2核2G3M带宽轻量服务器一年61元&#xff0c;折合5元1个月&#xff0c;新老用户同享99元一年服务器&#xff0c;2核4G5M服务器ECS优惠价199元一年&#xff0c;2核4G4M轻量服务器165元一年&#xff0c;2核4G服务器30元3…

解线性方程组(二)——Jacobi迭代法求解(C++)

迭代法 相比于直接法求解&#xff0c;迭代法使用多次迭代来逐渐逼近解&#xff0c;其精度比不上直接法&#xff0c;但是其速度会比直接法快很多&#xff0c;计算精度可控&#xff0c;特别适用于求解系数矩阵为大型稀疏矩阵的方程组。 Jacobi迭代法 假设有方程组如下&#xf…

QGIS004:【08图层工具箱】-导出到电子表格、提取图层范围

摘要&#xff1a;QGIS图层工具箱常用工具有导出到电子表格、提取图层范围等选项&#xff0c;本文介绍各选项的基本操作。 实验数据&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1ZK4_ShrQ5BsbyWfJ6fVW4A?pwdpiap 提取码&#xff1a;piap 一、导出到电子表格 工具…

OpenAl 视频生成模型 —— Sora技术报告解读

这里是陌小北&#xff0c;一个正在研究硅基生命的碳基生命。正在努力成为写代码的里面背诗最多的&#xff0c;背诗的里面最会写段子的&#xff0c;写段子的里面代码写得最好的…厨子。 写在前面 早上醒来&#xff0c;就看到OpenAl推出的视频模型Sora炸锅了&#xff0c;感觉所…

代码随想录 Leetcode452. 用最少数量的箭引爆气球

题目9&#xff1a; 代码&#xff08;首刷看解析 2024年2月17日&#xff09;&#xff1a; class Solution { private:const static bool cmp(vector<int>& a, vector<int>& b) {return a[0] < b[0];} public:int findMinArrowShots(vector<vector<…

Linux下解压tar.xz文件的命令

tar -c: 建立压缩档案-x&#xff1a;解压-t&#xff1a;查看内容-r&#xff1a;向压缩归档文件末尾追加文件-u&#xff1a;更新原压缩包中的文件 ------------------------------------------ 这五个是独立的命令&#xff0c;压缩解压都要用到其中一个&#xff0c;可以和别的…

如何用Qt实现一个无标题栏、半透明、置顶(悬浮)的窗口

在Qt框架中&#xff0c;要实现一个无标题栏、半透明、置顶&#xff08;悬浮&#xff09;的窗口&#xff0c;需要一些特定的设置和技巧。废话不多说&#xff0c;下面我将以DrawClient软件为例&#xff0c;介绍一下实现这种效果的四个要点。 要点一&#xff1a;移除标题栏&#…

定时器外部时钟

一、相较于内部时钟中断改动&#xff1a; 1.Timer.c RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin GPIO_Pin_…

BUGKU-WEB 头等舱

题目描述 题目截图如下&#xff1a; 进入场景看看&#xff1a; 解题思路 先看看源码再看看F12请求和响应 相关工具 略 解题步骤 查看源码&#xff0c;好家伙真的什么也没有 2. 看看F12请求和响应&#xff0c;找到了 得到Flag flag{a49c7aba1014c3673ec9982946d0545a…

fastposter v2.18.0 一分钟完成开发海报-云服务来袭

fastposter v2.18.0 一分钟完成开发海报-云服务来袭 fastposter 是一款快速开发海报的工具&#xff0c;已经服务众多电商、行业海报、分销系统、电商海报、电商主图等海报生成和制作场景。 什么是 fastposter &#x1f525;&#x1f525;&#x1f525;fastposter 是一款海报…

【数据结构】16 二叉树的定义,性质,存储结构(以及先序、后序、中序遍历)

二叉树 一个二叉树是一个有穷的结点集合。 它是由根节点和称为其左子树和右子树的两个不相交的二叉树组成的。 二叉树可具有以下5种形态。 性质 一个二叉树第i层的最大结点数为 2 i − 1 2^{i-1} 2i−1, i ≥ 1 i \geq 1 i≥1 每层最大结点可以对应完美二叉树&#xff08;…