【图论——第四讲】dijkstra算法求单源最短路及其堆优化

2023-10-29

ฅ(๑˙o˙๑)ฅ 大家好, 欢迎大家光临我的博客:面向阿尼亚学习
算法学习笔记系列持续更新中~

阿



一、前言

单源最短路,指的是求一个点,到其他所有点的最短距离。即起点是固定的,单一的

注意:最短路问题的核心在于,把问题抽象成一个最短路问题,并建图。图论相关的问题,不侧重于算法原理,而侧重于对问题的抽象。

所有边的权重都是正数,通常有两种算法
1.朴素Dijkstra
时间复杂度O(n2),其中n是图中点的个数,m是边的个数
2.堆优化版的Dijkstra
时间复杂度O(mlogn),其中n是图中点的个数,m是边的个数

两者孰优孰劣,取决于图的疏密程度即点数n,与边数m的大小关系当是稀疏图(n和m是同一级别)时,可能堆优化版的Dijkstra会好一些。当是稠密图时(m和n2是同一级别),使用朴素Dijkstra会好一些。
稠密图指的是边的条数|E|接近于|V|²,稀疏图是指边的条数|E|远小于于|V|²(数量级差很多)

下面就让我们了解一下dijkstra算法求单源最短路及其堆优化


二、朴素dijkstra算法

迪杰斯特拉算法不能用于带负权边。

时间复杂是 O(n2+m), n 表示点数,m 表示边数

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为正值。
请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1。
第一行包含整数 n 和 m。
接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。
输出一个整数,表示 1 号点到 n 号点的最短距离。
如果路径不存在,则输出 −1。
输入:
3 3
1 2 2
2 3 1
1 3 4
输出:
3

Dijkstra 的整体思路比较清晰
即进行n(n为n的个数)次迭代去确定每个点到起点的最小值 最后输出的终点的即为我们要找的最短路的距离

所以按照这个思路除了存储图外我们还需要存储两个量

dist[n] //用于存储每个点到起点的最短距离
st[n]   //用于在更新最短距离时 判断当前的点的最短距离是否确定 是否需要更新

每次迭代的过程中我们都先找到当前未确定的最短距离的点中距离最短的点

int t=-1;       //将t设置为-1 因为Dijkstra算法适用于不存在负权边的图
for(int j=1;j<=n;j++)
{
    if(!st[j]&&(t==-1||dist[t]>dist[j])    //该步骤即寻找还未确定最短路的点中路径最短的点
        t=j;
}

通过上述操作当前我们的t代表就是剩余未确定最短路的点中 路径最短的点
而与此同时该点的最短路径也已经确定我们将该点标记

st[t]=true;

然后用这个去更新其余未确定点的最短距离

for(int j=1;j<=n;j++)
    dist[j]=min(dist[j],dist[t]+g[t][j]);
//这里可能有同学要问j如果从1开始的话 会不会影响之前已经确定的点的最小距离
//但其实是不会 因为按照我们的Dijkstra算法的操作顺序 先确定最短距离的点的距离已经比后确定的要小 所以不会影响
//当然你也可以在循环判断条件里加上if(!st[i])
//这里j从1开始只是为了代码的简洁

进行n次迭代后最后就可以确定每个点的最短距离
然后再根据题意输出相应的 要求的最短距离

AC代码

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=510;

int g[N][N];    //为稠密阵所以用邻接矩阵存储
int dist[N];   //用于存储每个点到起点的最短距离
bool st[N];      //用于在更新最短距离时 判断当前的点的最短距离是否确定 是否需要更新

int n,m;

int Dijkstra()
{
    memset(dist, 0x3f,sizeof dist);     //初始化距离  0x3f代表无限大

    dist[1]=0;  //第一个点到自身的距离为0

    for(int i=0;i<n;i++)      //有n个点所以要进行n次 迭代
    {
        int t=-1;       //t存储当前访问的点
         //将t设置为-1 因为Dijkstra算法适用于不存在负权边的图

        for(int j=1;j<=n;j++)   //这里的j代表的是从1号点开始
            if(!st[j]&&(t==-1||dist[t]>dist[j]))     
                t=j;//该步骤即寻找还未确定最短路的点中路径最短的点

        st[t]=true;   

        for(int j=1;j<=n;j++)           //依次更新每个点所到相邻的点路径值
            dist[j]=min(dist[j],dist[t]+g[t][j]);
    }

    if(dist[n]==0x3f3f3f3f) return -1;  //如果第n个点路径为无穷大即不存在最低路径
  
    return dist[n];//可以遍历所有的dist
}
int main()
{
    cin>>n>>m;

    memset(g,0x3f,sizeof g);    //初始化图 因为是求最短路径
                                //所以每个点初始为无限大

    while(m--)//读入边
    {
        int x,y,z;
        cin>>x>>y>>z;
        g[x][y]=min(g[x][y],z);     //如果发生重边的情况则保留最短的一条边
    }

    cout<<Dijkstra()<<endl;
    return 0;
}

三、堆优化版dijkstra

时间复杂度 O(mlogn), n 表示点数,m 表示边数

堆可以自己手写(用数组模拟),也可以使用现成的(C++的STL提供了priority_queue,Java的JDK中提供了PriorityQueue)
特别注意,插入堆的操作,由于更新距离时,可能对一些距离已知的点进行更新(更新为更小的距离),此时不能因为这个点已经在堆中就不进行插入了,因为其距离已经变了,堆中原有的节点已经无效了,按理说,应该修改堆中对应节点的距离值,然后做调整,实际上,可以直接插入一个新的节点(此时对于同一个节点,堆中有两份),但没有关系,堆中的重复节点不会影响最终的结果。

堆优化版的dijkstra是对朴素版dijkstra进行了优化,在朴素版dijkstra中时间复杂度最高的寻找距离最短的点O(n^2)可以使用最小堆优化。

  1. 一号点的距离初始化为零,其他点初始化成无穷大。
  2. 将一号点放入堆中。
  3. 不断循环,直到堆空。每一次循环中执行的操作为:
    弹出堆顶(与朴素版diijkstra找到S外距离最短的点相同,并标记该点的最短路径已经确定)。
    用该点更新临界点的距离,若更新成功就加入到堆中。

AC代码

#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>//堆的头文件

using namespace std;

typedef pair<int, int> PII;//堆里存储距离和节点编号

const int N = 1e6 + 10;

int n, m;//节点数量和边数
int h[N], w[N], e[N], ne[N], idx;//邻接表存储图
int dist[N];//存储距离
bool st[N];//存储状态

void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}

int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);//距离初始化为无穷大
    dist[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;//ver:节点编号,distance:源点距离ver 的距离

        if (st[ver]) continue;//如果距离已经确定,则跳过该点
        st[ver] = true;

        for (int i = h[ver]; i != -1; i = ne[i])//更新ver所指向的节点距离
        {
            int j = e[i];
            if (dist[j] > dist[ver] + w[i])
            {
                dist[j] = dist[ver] + w[i];
                heap.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);
    }

    cout << dijkstra() << endl;

    return 0;
}

最后

莫言真理无穷尽,寸进自有寸进欢

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【图论——第四讲】dijkstra算法求单源最短路及其堆优化 的相关文章

随机推荐

  • linux命令之cd,ls,vi进入及退出文件

    一 cd用来进入指定的某个目录 说cd这个命令是Linux上使用率最高的两个命令之一不为过吧 另一个当然是ls了 前两天看到了一个cd命令的小技巧是我一直都不知道的 呵呵 这里顺便记下来 cd 回到上次所在目录 感觉还是比较有用 省略了很多
  • 关于“No subject alternative DNS name matching”的解决

    最近突然后台报错 I O error on POST request for https test xxxxxxx com api xxx xxx xxx java security cert CertificateException No
  • RHP-Zero

    https www powerelectronics com technologies power management article 21860287 understanding the righthalfplane zero part
  • python作品-python实例作品

    广告关闭 腾讯云双11爆品提前享 精选热门产品助力上云 云服务器首年88元起 买的越多返的越多 最高满返5000元 多尺度模板匹配结果不要拿我的话来说 这种方法的作品 我们来看一些例子 打开您的终端并执行以下命令 multi scale t
  • unity3d coroutine、invoke的应用

    提供了两种异步方式的调用 1 coroutine 协程 应该是untity对c 多线程的一种封装吧 内部不是很了解 调用的函数需标示IEnumerator迭代配合yield return xxx使用 yield标示着是否暂停迭代 yield
  • 荣耀Magicbook安装黑苹果教程(OpenCore引导)

    荣耀笔记本电脑Magicbook安装黑苹果双系统教程 有空再写 可以先看下面的参考资料 准备工作 系统 macOS 12 3 1 Monterey 21E258 u盘 两个 一个用于安装黑苹果系统 一个用于引导修复 磁盘分区等工作 无线网卡
  • Java 正确的做字符串编码转换

    Java 正确的做字符串编码转换 字符串的内部表示 字符串在java中统一用unicode表示 即utf 16 LE 对于 String s 你好哦 如果源码文件是GBK编码 操作系统 windows 默认的环境编码为GBK 那么编译时 J
  • 2013年度总结 -- 向着IT前进

    各位朋友 请将手机调整到飞行模式 我们将乘时光机回到2013年元月 一起见证作者Mr Chen在过去这一年里的 丰功伟绩 现在开始闭上眼睛 进入倒计时10 9 8 7 6 5 4 3 2 1 2013年元月 上线前的冲刺 兄弟们 辛苦一下
  • 【工具使用】STM32CubeMX-DMA配置(ADC+DMA 和 UART+DMA)

    一 概述 无论是新手还是大佬 基于STM32单片机的开发 使用STM32CubeMX都是可以极大提升开发效率的 并且其界面化的开发 也大大降低了新手对STM32单片机的开发门槛 本文主要讲述STM32芯片的DMA的配置及其相关知识 二 软件
  • 计算机快捷键大全截图,电脑截图快捷键是哪个?电脑快捷键使用大全

    原标题 电脑截图快捷键是哪个 电脑快捷键使用大全 在电脑日常工作中 截图是经常会使用到的功能 相信绝大数的用户都是通过第三方截图软件 比如QQ 旺旺等程序自带的电脑截图功能 却不知道Win系统中也是自带截图工具 和键盘上某键配合使用 键盘上
  • Vue 路由的params参数

    1 路由的params参数 1 配置路由 声明接收params参数 routes path about component About component Home children path news component News com
  • android flash无图标,Android - Android - 安装应用(APP) 不显示桌面图标、隐藏图标

    PackageManager COMPONENT ENABLED STATE ENABLED 显示应用图标 PackageManager COMPONENT ENABLED STATE DISABLED 隐藏应用图标 我用这俩个值来显示和隐
  • 天龙3d服务器维护,《新天龙八部》2017年3月6日全服更新维护公告

    亲爱的玩家 大家好 为保证游戏运行的稳定性 提升整体服务质量 新天龙八部 游戏全部服务器 部分服务器将提前至5 00维护 具体服务器列表请见公告下方 将于2017年3月6日7 00 9 00进行更新维护 维护后版本号升级为3 61 5303
  • -bash: /usr/bin/yum: No such file or directory解决方案

    删除了yum文件 导致yum命令出现 bash情况 root localhost yum bash usr bin yum No such file or directory 解决方案 http mirrors 163 com centos
  • el-select下拉框:数据回显后,无法重新选中或修改

    选中其他值以后 数据并没有发生改变 且无法选中 解决 给el select 点击事件 change getTeacherId 强制数据刷新 表单同理 input getTeacherId getTeacherId val this next
  • 数据可视化第四章

    比例数据 是根据类别 子类别和群体来进行划分的数据 对于比例 通常想要得到最大值 最小值和总体分布 前两者比较简单 将数据由小到大进行排列 位于两端的分别就是最小值和最大值 数据对比也是比例可视化的一个重要应用 在一个图表中集中反映多个维度
  • 小程序页面滚动穿透

    小程序页面滚动穿透 一 场景 框架 Taro2 Taro3不生效的 在项目当中 基础遇到这样的需求 有一个长列表 或者其他可滚动展示的页面 在这个页面会弹出一个Modal层 如下 贝壳找房的 的筛选栏 二 问题 如果这个弹框内容不可滚动 不
  • java 获取系统 默认编码_Java获取Linux服务器系统默认编码格式

    一 查找java进程 ps ef grep java 二 使用jinfo命令查看java系统参数 jinfo sysprops 进程id Usage jinfo option to connect to running process ji
  • 建立良好人际关系的原则

    1 尊重原则 尊重包括两个方面 自尊和尊重他人 自尊就是在各种场合都要尊重自己 维护自己的尊严 不要自暴自弃 尊重他人就是要尊重别人的生活习惯 兴趣爱好 人格和价值 只有尊重别人才能得到别人的尊重 2 真诚原则 只有诚以待人 胸无城府 才能
  • 【图论——第四讲】dijkstra算法求单源最短路及其堆优化

    o 大家好 欢迎大家光临我的博客 面向阿尼亚学习 算法学习笔记系列持续更新中 文章目录 一 前言 二 朴素dijkstra算法 三 堆优化版dijkstra 最后 一 前言 单源最短路 指的是求一个点 到其他所有点的最短距离 即起点是固定的