【第二十二课】最短路:dijkstra算法 ( acwing849 / acwing850 / c++ 代码)

目录

dijkstra算法求最短距离步骤

朴素的dijkstra算法---acwing-849

代码如下

代码思路 

堆优化版的dijkstra算法---acwing-850

代码如下


关于最短路问题分有好几种类型 :

单源就是指:只求从一个顶点到其他各顶点

多源是指:要求每个顶点到其他各顶点 

这些情况对应有不同的算法,这次先介绍dijkstra算法的两种。 

dijkstra算法求最短距离步骤

我们手写的步骤就是:

1.

确定我们要处理的单源点。即我们是想 从哪个顶点开始寻找到其他顶点的最短路径。

2.

第一轮:看该顶点到其他任意顶点的距离并记录下来。一般只有直连的顶点是边的权重,其他不直连的都是正无穷,每个顶点都看过之后,选出这些记录下来的距离的最小值所对应的顶点编号。

3.

相当于第二轮的时候,我们可以看作,起始顶点是上一轮选出的最小距离的顶点,且起步价就是初始值是这个最小距离。由此不断迭代直到寻找过所有顶点到开始顶点的最短距离。【我觉得这种思路比较好理解,对应下面视频讲解的第二个】

 如下图 (INF表示的是正无穷)

关于该算法的一些视频讲解的推荐:

 【图-最短路径-Dijkstra(迪杰斯特拉)算法】

【【全网第二清晰】手写迪杰斯特拉-Dijkstra(考试用)】

讲的都很清晰,可以看一下

朴素的dijkstra算法---acwing-849

代码如下

步骤明白之后代码的含义需要解释的都写在注释里了。 

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=510;
int n,m;
int g[N][N];//用邻接矩阵来存储稠密图,二维数组的每一位表示【行标指向列标的边 所对应的权重】
int dist[N];//存储从起点到其他节点当前的最短距离
bool st[N];//标记该点是否已经已经被寻找过

int dijkstra()
{
    memset(dist,0x3f,sizeof dist);//初始状态所有的距离都是正无穷
    dist[1]=0;
    //习惯将节点从1开始编号,且本题求的就是1节点到其他节点的最短距离。该点到其自身的距离为0

    //确保了寻找了每个节点到源节点的最短路径
    for(int i=0;i<n;i++)
    {
        int t=-1;// 用于标记当前轮次中【距离最短的未访问节点的编号】,初始化为 -1 表示尚未找到有效节点
        for(int j=1;j<=n;j++)
        {
            if(!st[j] && (t==-1 || dist[t]>dist[j]))
            {
                t=j;//找到当前轮次中距离最短的未访问节点的编号
            }
        }
        st[t]=1;//找到后将其标记为1

        //通过选定的节点更新到其他节点的最短距离
        for(int j=1;j<=n;j++)
        {
            dist[j]=min(dist[j],dist[t]+g[t][j]);//g[t][j]表示经过节点t到达节点j的路径长度
        }
    }
    if(dist[n]==0x3f3f3f3f)return -1;
    return dist[n];
}
int main()
{
    cin>>n>>m;
    memset(g,0x3f,sizeof g);
    while(m--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        g[a][b]=min(g[a][b],c);//面对多重边的情况 取权值小的边
    }

    int t=dijkstra();
    cout<<t;
    return 0;
}

代码思路 

1.根据题目中的数据范围,边数远远大于顶点数,因此是稠密图,且用邻接矩阵存储图。 而这里每条边都会有各自权值,因此用邻接矩阵加边直接更改二维数组中对应位置为对应权重即代表了存在权值为x的边不用单独写添加边的函数。

2.求1->n任意一个顶点的最短距离,使用dijkstra算法。单独分装函数,函数内部也就是代码实现该算法的步骤。

3.dijkstra函数内部。首先初始化dist数组值为正无穷。注意dist数组的含义是:下标表示顶点,该数组表示下标对应的顶点距起始顶点的最短距离。由于我们是从1号顶点开始,且其自身到自身的距离应该是0,由此初始dist[1]=0 ;

之后就开始经过n轮寻找,确保每一个顶点都进行了寻找,因此外层循环次数为n次。由于只是控制次数,所以从0~n-1的循环条件是可以的,当然也可以写1~n

需要创建一个st数组做标记,标记那些已经找到最短距离的点。下标表示点的编号。

每次寻找需要做什么?观察所有顶点(内层for循环),找到距离源点距离最短的顶点,标记该顶点已经找到最短距离,之后遍历所有顶点,更新最短距离,看加了这个点之后其他有没有哪个点有更优的最短距离,进行更改即可。

这段代码的时间复杂度最差是O(n^2),与边数m无关,因此适用于稠密图。 

堆优化版的dijkstra算法---acwing-850

这道题的区别就是n和m的取值范围是相同的,都是1.5e5 ,该图为稀疏图。首先不同的就是这道题会采用邻接表存储图。

代码上的不同主要就是:利用堆来简化循环的嵌套,降低时间复杂度。

之前写的关于堆的文章,可以回顾一下。

手写堆

【第十五课】数据结构:堆 (“堆”的介绍+主要操作 / acwing-838堆排序 / 时间复杂度的分析 / c++代码 )

【第十五课】数据结构:堆(acwing-839模拟堆 / ph和hp数组的映射关系 /c++代码 )

stl优先队列

【第十七课】c++常用的STL容器

代码如下

我们这里使用优先队列实现。 

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>//使用优先队列
using namespace std;
typedef pair<int,int> PII;//第一个元素表示最短距离,第二个元素表示顶点编号
const int N=1.5e5+10;
int n,m;
int h[N],e[N],ne[N],w[N],idx;
int dist[N];//存储从起点到其他节点当前的最短距离
bool st[N];//标记该点是否已经被处理过

void add(int a,int b,int c)
{
    e[idx]=b;
    ne[idx]=h[a];
    w[idx]=c;
    h[a]=idx++;
}
int dijkstra()
{
    memset(dist,0x3f,sizeof dist);//初始状态所有的距离都是正无穷
    dist[1]=0;//习惯将节点从1开始编号,且本题求的就是1节点到其他节点的最短距离。该点到其自身的距离为0
    priority_queue<PII,vector<PII>,greater<PII>> he;//创建小根堆
    he.push({0,1});//先将源点加入队列

    while(he.size())//当队列不为空
    {
        PII t=he.top();
        he.pop();//将当前的最短距离出队

        int ver=t.second,distance=t.first;//ver表示顶点 distance表示最短距离
        if(st[ver])continue;//如果这个顶点已经处理过就直接跳过
        for(int i=h[ver];i!=-1;i=ne[i])//遍历这个点的所有直连的边
        {
            int j=e[i];
            if(dist[j]>distance+w[i])//更新与其直连的点的最短距离
            {
                dist[j]=distance+w[i];
                he.push({dist[j],j});
            }
        }
    }
    if(dist[n]==0x3f3f3f3f)return -1;
    return dist[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=dijkstra();
    cout<<t;
    return 0;
}

注意这里其实并没有处理重边,这是因为:我们是按照逐个顶点遍历其所连的边处理的,对于重边我们会和该顶点的其他边一样,进行平等的判断,得出一个最短距离的边只有最短的边会在当前阶段影响最短路径

使用优先队列所优化的是求最短距离这一步,本来需要遍历所有节点,找到离源点距离最小的点,时间复杂度为 O(n),通过优先队列实现小根堆,堆顶是最小值,直接将这一步优化为O(1)


感觉堆优化版的更好理解一点,,朴素的做法每层循环的功能要搞明白,清楚执行的什么操作。

好啦先写到这里。

有问题欢迎指出,一起加油!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于springboot+vue的旅游管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 研究现状…

uniapp顶部导航栏高度适配

为了实现好看又实用的顶部导航栏&#xff0c;不得不自己定义导航栏样式。而自己定义的导航栏高度会因为手机的型号不同所展示的效果也就不同&#xff0c;所以只能通过适配高度来达到预期的效果 1.需要在page.json文件中对需要自定义导航栏文件进行配置 "navigationStyle…

Leetcode第382场周赛

Leetcode第382场周赛 本人水平有限&#xff0c;只做前三道。 一、按键变更的次数 给你一个下标从 0 开始的字符串 s &#xff0c;该字符串由用户输入。按键变更的定义是&#xff1a;使用与上次使用的按键不同的键。例如 s “ab” 表示按键变更一次&#xff0c;而 s “bBBb”…

机器学习:梯度下降法(Python)

LinearRegression_GD.py import numpy as np import matplotlib.pyplot as pltclass LinearRegression_GradDesc:"""线性回归&#xff0c;梯度下降法求解模型系数1、数据的预处理&#xff1a;是否训练偏置项fit_intercept&#xff08;默认True&#xff09;&…

【数据分享】1929-2023年全球站点的逐月最高气温数据(Shp\Excel\无需转发)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff0c;其中又以气温指标最为常用&#xff01;说到气温数据&#xff0c;最详细的气温数据是具体到气象监测站点的气温数据&#xff01; 之前我们分享过1929-2023年全球气象站…

C# Onnx yolov8 仪表指针检测

目录 效果 模型信息 项目 代码 训练数据 下载 C# Onnx yolov8 仪表指针检测 效果 模型信息 Model Properties ------------------------- date&#xff1a;2024-01-31T11:19:38.828556 author&#xff1a;Ultralytics task&#xff1a;detect license&#xff1a;AGPL-…

wordpress怎么做产品展示站?推荐使用MOK主题和ent主题

大多数WordPress站点都是个人博客网站&#xff0c;主要以文章性质的图文为主。不过部分站长想要用WordPress搭建一个产品展示站&#xff0c;应该怎么做呢&#xff1f; 其实&#xff0c;WordPress可以用来建立各种各样的博客网站&#xff0c;包括个人博客、企业网站、商城、影视…

小白级教程,10秒开服《幻兽帕鲁》

在帕鲁的世界&#xff0c;你可以选择与神奇的生物「帕鲁」一同享受悠闲的生活&#xff0c;也可以投身于与偷猎者进行生死搏斗的冒险。帕鲁可以进行战斗、繁殖、协助你做农活&#xff0c;也可以为你在工厂工作。你也可以将它们进行售卖&#xff0c;或肢解后食用。 前言 马上过年…

带大家详细了解msvcr120.dll丢失的原因,msvcr120.dll丢失怎样修复的方法

在使用电脑和运行应用程序时&#xff0c;我们经常会遇到与动态链接库&#xff08;Dynamic Link Library, DLL&#xff09;文件相关的错误。其中之一是 "msvcr120.dll 丢失" 的错误提示。今天我们就来详细的了解一下msvcr120.dll这个文件和分享msvcr120.dll丢失怎样修…

从宏观上对人工智能(AI)的一些理解

1.人工智能概述 68年前&#xff0c;约翰麦卡锡在“达特茅斯会议”正式提出人工智能概念。直到2023年&#xff0c;ChatGPT掀起全球AI大模型浪潮&#xff0c;英伟达市值一年飙涨2.4倍&#xff0c;真正意义上的“人工智能元年”到来了。 提到人工智能&#x…

事件驱动架构:使用Flask实现MinIO事件通知Webhooks

MinIO的事件通知可能一开始看起来并不激动人心&#xff0c;但一旦掌握了它们的力量&#xff0c;它们就能照亮您存储桶内的动态。事件通知是一个全面、高效的对象存储系统中的关键组件。Webhooks是我个人最喜欢的工具&#xff0c;用于与MinIO集成。它们在事件的世界中就像一把瑞…

八种Flink任务监控告警方式

目录 一、Flink应用分析 1.1 Flink任务生命周期 1.2 Flink应用告警视角分析 二、监控告警方案说明 2.1 监控消息队中间件消费者偏移量 2.2 通过调度系统监控Flink任务运行状态 2.3 引入开源服的SDK工具实现 2.4 调用FlinkRestApi实现任务监控告警 2.5 定时去查询目标库…

在深度学习中,epoch和learning rate的通常取值范围?

在深度学习中&#xff0c;epoch和学习率的取值确实会根据不同的任务、数据集和模型架构有所不同。然而&#xff0c;您提到的范围是一些常见的经验性取值&#xff0c;这些取值在很多情况下都能工作得相当好。 1. 对于epoch的取值范围&#xff1a; 在很多研究论文和实际应用中&…

机器学习 | 掌握逻辑回归在实践中的应用

目录 初识逻辑回归 逻辑回归实操 分类评估方法 初识逻辑回归 逻辑回归&#xff08;LogisticRegression&#xff09;是机器学习中的一种分类模型&#xff0c;逻辑回归是一种分类算法&#xff0c;虽然名字中带有回归&#xff0c;但是它与回归之间有一定的联系。由于算法的简单…

tui-datetime组件由弹窗显示改成页面直接展示

效果图 代码 <template><view class"tui-datetime-picker" :style"{zIndex}"><view class"tui-datetime__header" :class"{ tui-show: isShow }" :style"{zIndex:getPickerZIndex}"><view class&quo…

论文阅读-一个用于云计算中自我优化的通用工作负载预测框架,

论文标题&#xff1a;A Self-Optimized Generic Workload Prediction Framework for Cloud Computing 概述 准确地预测未来的工作负载&#xff0c;如作业到达率和用户请求率&#xff0c;对于云计算中的资源管理和弹性非常关键。然而&#xff0c;设计一个通用的工作负载预测器…

spring-boot-admin的介绍和使用

概述 Spring Boot 有一个非常好用的监控和管理的源软件&#xff0c;这个软件就是 Spring Boot Admin。该软件能够将 Actuator 中的信息进行界面化的展示&#xff0c;也可以监控所有 Spring Boot 应用的健康状况&#xff0c;提供实时警报功能。 主要的功能点有&#xff1a; 显…

springboot集成rocketmq-spring-boot-starter的坑(避坑指南)

1.说明版本&#xff08;解决方法&#xff09; springboot版本&#xff1a;2.2.2.RELEASE RocketMQ版本&#xff1a;rocketmq-spring-boot-starter 2.2.2 2.坑 rocketmq-spring-boot-starter的版本一开始&#xff0c;使用的是2.2.0版本&#xff0c;一直出现一个问题&#x…

leetcode刷题(剑指offer) 101.对称二叉树

101.对称二叉树 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false提示&#xff1a; …

探究HMAC算法:消息认证与数据完整性的完美结合

Hash-based Message Authentication Code&#xff08;基于哈希的消息认证码&#xff0c;简称HMAC&#xff09;算法作为一种广泛应用的消息认证码&#xff08;MAC&#xff09;算法&#xff0c;在现代信息安全领域起着至关重要的作用。本文将从算法原理、优缺点、实际应用等方面&…