算法基础14 —— 图论入门之迪杰斯特拉算法(Dijkstra)

2023-11-03

回顾

  • Floyed算法可以求任意两点之间的最短路径,但是Dijkstra算法只能求一个结点到另一个结点的最短路径,它是一个单源的最短路径算法
  • Floyed算法的时间复杂度为O(n^3),故一般情况下数据范围要求在100以内

Dijkstra算法描述

  • 设起点为s,dis[v]表示从s到v的最短路径长度, 如dis[3] = 6表示从起点到3号结点的最短路径为6
  • pre[v]为v的前驱节点,用来输出路径
  • 初始化:
dis[v] =(v ≠ s);//初始时路径为无穷 
dis[s] = 0;//s -> s的路径为0 
pre[s] = 0; 
  • 伪代码:
for (i = 1; i <= n ; i++)
{
    //1.在没有被访问过的点中找一个顶点u使得dis[u]是最小的
    //2.把u标记为已确定最短路径
    //3.For循环遍历:与u相连的每个未确定最短路径的顶点v
    //如果结点u的加入使得s->v的距离dis[v]变小,则更新
    if (dis[u] + w[u][v] < dis[v]) 
    {
        dis[v] = dis[u] + w[u][v];
        pre[v] = u;
    }
}

可以通过下图来理解为什么要更新dis[v] = dis[u] + w[u][v]
在这里插入图片描述

  • 算法结束:dis[v]为s到v的最短距离;pre[v]为v的前驱节点,用来输出路径。

算法的总体思想:

首先设置一个空集合,并且将所有的结点分成两类,一类是确定了最短路径的结点,另一类是未确定最短路径的结点。每次向集合中加入一个可以确定最短路的结点,然后判断会不会因为该点的加入使得某个结点到其他结点的距离变得更短,如果是,则更新最短距离。

这么多伪代码,是不是很抽象有点晕了?下面来看一个例子

Dijkstra算法举例

例:根据下图a,找出从节点1出发到各个节点的最短路径长度。
在这里插入图片描述

  • 算法开始时,作为起点的dis[1] = 0//结点1到其自身的距离为0
    结点1到其他结点的距离为无穷,即dis[i] = 0x3f3f3f3f
    在这里插入图片描述
    在这里插入图片描述

  • 第一轮循环发现dis[1] = 0最小,将结点1标记成已经确定最短路径的结点(1号结点的加入会影响1号结点到2、3和4号结点的距离)。另外还需要根据图a对所有的绿点做出修改,使得dis[2] = 2dis[3] = 4dis[4] = 7
    在这里插入图片描述
    在这里插入图片描述

  • 第二轮循环发现1号结点除外,dis[2] = 2最小,将结点2标记成已经确定最短路径的结点(2号结点的加入只会影响1号结点到3和5号结点的距离)。另外还需要根据图a对其余绿色结点做出修改,使得dis[3] = 3dis[5] = 4
    在这里插入图片描述

在这里插入图片描述

  • 第三轮循环发现除1、2号结点外,dis[3] = 3最小,将结点3标记成已经确定最短路径的结点(3号结点的加入会影响1号结点到4和5号结点的距离)。另外还需要根据图a对其余绿色结点做出修改,使得dis[4] = 4dis[5] = 4
    在这里插入图片描述
    在这里插入图片描述

  • 第四轮循环发现只有4号和5号结点还没有加入"集合",因为dis[4] = dis[5] = 4,又因为4号结点无法直接到达5号结点,故可以将4号结点直接加入,不需要对dis数组做出修改。

  • 最后只剩下一个五号结点没有加入集合,将其加入即可,从而得到1号结点到其余各个结点之间的最短距离如下图:
    在这里插入图片描述

在这里插入图片描述

看到这个粉绿粉绿的东西,突然…在这里插入图片描述
圣斗士星矢!仙女座登场!!
在这里插入图片描述

迪杰斯特拉代码模板

//迪杰斯特拉算法模板
//求源点s到其余各点的最短路径
void dijkstra(int s)
{
    memset(vis,0,sizeof vis);//1表示已经确定最短路径的点,0表示还未确定最短路径的点

    //初始时将s到所有点的路径设置为无穷
    memset(dis,0x3f,sizeof dis);

    dis[s] = 0;//结点s到s的距离为0
    while (1)//直到将所有的点都设置为已经访问,结束循环
    {
        int u = 0,min = INF;
        for (int j = 1;j <= n;j++)//用j遍历dis数组,每次遍历都会确定一个最短路的结点
        {
            if (!vis[j] && min > dis[j])//当前结点未被访问过
            {
                u = j;//u保存确定的最短路结点
                min = dis[j];//保存当前dis数组中的最短路径
            }
        }
        if (u == 0) return;//所有的点都被访问过,结束循环
        vis[u] = 1;//将其设置为已经访问过的点
        for (int v = 1;v <= n;v++)//最后的循环用来更新dis数组
            if (dis[v] > dis[u] + w[u][v])//将u结点加入之后路径变短
                dis[v] = dis[u] + w[u][v];
    }
}

Dijkstra算法总结

Dijkstra算法的时间复杂度为O(n^2),它是用来计算从一个点到其他所有点的最短路径的算法,是一种单源最短路径算法。也就是说,只能计算起点只有一个的情况。**它不能处理存在负边权的情况。**那么,为什么迪杰斯特拉算法不能处理负的边权呢?举个例子:
在这里插入图片描述
在上图中,结点2到结点3的权值为-4,显然从起点1到3的最短路径是-2,即1 → 2 → 3,但是dijskstra在第二轮循环开始时会找到当前dis[i]最小的点3,并标记它为白点。这时的dis[3] = 1,然而1却不是从起点到点3的最短路径。因为3已被标记为白点,最短路径值dis[3]不会再被修改了,所以我们在边权存在负数的情况下得到了错误的答案。

  • 第一次循环
    在这里插入图片描述
  • 第二次循环
    在这里插入图片描述

例题以及AC代码
Acwing 849 Dijkstra求最短路 I

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

int n,m;
const int N = 510;
const int INF = 0x3f3f3f3f;
int dis[N];//表示源点到其余各点的最短距离
int w[N][N];//w[i][j]表示i到j的路径
int vis[N];//vis[i]=0表示当前结点没被访问过,否则已经被访问过

//迪杰斯特拉算法模板
//求源点s到其余各点的最短路径
void dijkstra(int s)
{
    memset(vis,0,sizeof vis);//1表示已经确定最短路径的点,0表示还未确定最短路径的点
    
    //初始时将s到所有点的路径设置为无穷
    memset(dis,0x3f,sizeof dis);
    
    dis[s] = 0;//结点s到s的距离为0
    while (1)//直到将所有的点都设置为已经访问,结束循环
    {
        int u = 0,min = INF;
        for (int j = 1;j <= n;j++)//用j遍历dis数组,每次遍历都会确定一个最短路的结点
        {
            if (!vis[j] && min > dis[j])//当前结点未被访问过
            {
                u = j;//u保存确定的最短路结点
                min = dis[j];//保存当前dis数组中的最短路径
            }
        }
        if (u == 0) return;//所有的点都被访问过,结束循环
        vis[u] = 1;//将其设置为已经访问过的点
        for (int v = 1;v <= n;v++)//最后的循环用来更新dis数组
            if (dis[v] > dis[u] + w[u][v])//将u结点加入之后路径变短
                dis[v] = dis[u] + w[u][v];
    }
}

int main()
{
    memset(w,0x3f,sizeof w);
    scanf("%d%d",&n,&m);
    for (int i = 0;i < m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        w[x][y] = min(w[x][y],z);//有重边的情况,取最小值
    }
    //(dij可以省略)for (int i = 1;i <= n;i++) w[i][i] = 0;
    dijkstra(1);
    if (dis[n] > INF / 2) printf("-1\n");
    else printf("%d\n",dis[n]);
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

算法基础14 —— 图论入门之迪杰斯特拉算法(Dijkstra) 的相关文章

随机推荐

  • docker 端口映射错误解决方法

    COMMAND FAILED sbin iptables t nat A DOCKER p tcp d 0 0 dport 8111 j DNAT to destination 172 17 0 6 8111 i docker0 faile
  • [Android] 底部菜单布局+PopupWindows实现弹出菜单功能(初级篇)

    这篇文章主要是自己研究如何对底部菜单进行布局 并简单的实现点击不同 按钮 实现图片切换和背景切换的功能 最后通过PopupWindows实现弹出菜单 点击不同按钮能实现不同方法 相当于美图秀秀编辑图片的功能吧 它并没有涉及到Fragment
  • c++ 函数指针

    函数指针基础 1 获取函数的地址 2 声明一个函数指针 3 使用函数指针来调用函数 获取函数指针 函数的地址就是函数名 要将函数作为参数进行传递 必须传递函数名 声明函数指针 声明指针时 必须指定指针指向的数据类型 同样 声明指向函数的指针
  • 【Redis】深入理解 Redis 事务机制

    文章目录 前言 一 回顾 MySQL 事务 1 1 MySQL 事务的概念与特性 1 1 MySQL 事务的管理 二 对 Redis 事务的认识 2 1 什么是 Redis 的事务 2 1 1 Redis 事务的概念 2 1 2 对 Red
  • 虚拟机 Linux 系统自定义桌面分辨率且重启后保持不变

    这是原先写在博客园的 原标题为 Linux Ubuntu 虚拟机系统自定义桌面分辨率且重启后保持不变 现在做部分修改 适用于 Debian 系发行版 我用 VMware Workstation 12 Pro 安装的 Ubuntu MATE
  • 计算机图形学 期末复习 微课版 孔令德 七、建模与消隐 期末复习

    计算机中三维物体的表示有线框模型 表面模型和实体模型3种方法 模型的数据结构 三表结构 立方体的点表 顶点 x坐标 y坐标 z坐标 P0 X0 1 Y0 0 Z0 0 P1 X1 1 Y1 0 Z1 0 P2 X2 1 Y2 1 Z2 0
  • SpringBoot结合Eureka,配置服务端

    场景 为了对单一项目进行拆分 需要模块相互远程调用 负载均衡和限流 进而引入eureka 难点 1 springboot和springcloud版本对应关系 2 父子项目maven关系梳理 完成代码 1 父项目pom文件 creatived
  • DSB Security 如何优雅的进行敏感数据的传输?

    DSB Security 如何优雅的进行敏感数据的传输 对于项目中的敏感数据处理 很多同学刚开始接触的时候 往往觉得比较繁琐 项目中实现的方式也是千奇百怪 基本就是百度搜索和粘贴 对于敏感数据的处理 是任何一家互联网公司必须要注重的事情 用
  • OPENGL知识点整理(一)

    OPENGL知识点整理 一 概述内容为阅读相关博主文档后整理 因此 相当部分的内容直接引用自如下链接 https www jianshu com p 5da5a17ad5cb https blog csdn net u012861978 a
  • 一些抄袭CSDN的爬虫网站(长期收集更新)

    目录 一 CodeAntenna 1 简介 2 网址 二 编程学习网 1 简介 2 网址 三 待更新 本文由CSDN点云侠原创 爬虫网站请努力加油爬 一 CodeAntenna 1 简介 互联网耻辱柱排行榜Top 1 本人博客里任何一点免费
  • vscode远程连接linux服务器

    Linux服务器 或虚拟机 条件 开启ssh服务 客户端 vscode 1 服务端 服务端需要开启ssh服务vscode才能连接 首先检验linux是否开启了ssh服务 systemctl status sshd servie sshd s
  • 【ARIMA-WOA-CNN-LSTM】合差分自回归移动平均方法-鲸鱼优化-卷积神经网络-长短期记忆神经网络研究(Python代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 1 1 ARIMA模型 1 2 鲸鱼优化算法 1 3 卷积神经网络 1 4 LSTM 模型 2 运行结果
  • GPS数据解析 GPS 数据格式

    GPS 数据格式 NMEA 0183协议 GPS上电后 每隔一定的时间就会返回一定格式的数据 数据格式为 信息类型 x x x x x x x x x x x x x 每行开头的字符都是 接着是信息类型 后面是数据 以逗号分隔开 一行完整的
  • java程序开启远程调试、断点功能

    代码就是最好的文档 agentlib jdwp transport dt socket server y suspend n address 5005 几点说明 agentlib jdwp 这个是jdk自带的调试工具是jti 位于 JAVA
  • Linux下创建Vivado 2017.4工程以及相关配置

    Linux下创建Vivado 2017 4工程以及相关配置 一 创建Linux下的vivado工程的条件 在Windows10下安装VMware workstation full 12 5 7 20721 exe软件包 在Windows10
  • .git文件泄露

    知识点 git文件泄露 详情 简述 git文件导致的源码泄露 git文件是开发人员在开发过程中使用 Git 分布式版本控制系统 做开发时产生的隐藏目录 该文件包含一些版本信息和网站源码 数据库信息等敏感信息 原理利用 1 通常开发人员在开发
  • lightmapper

    https github com ands lightmapper
  • Mybatis在使用count和group_by查询时,mysql数据库5.7,报错

    Mybatis在使用count和group by查询时 mysql数据库5 7 报错 2023 05 31 20 49 09 792 ERROR 7548 io 8081 exec 10 o a c c C dispatcherServle
  • 混淆工具javascript-obfuscator使用简介

    javascript obfuscator是一个免费的JavaScript代码混淆工具 它功能强大 可以把你的源代码变得 面目全非 完全没有可读性 还具有部分防调试功能 给JavaScript代码多一层保护 安装 它支持很多流行的前端打包工
  • 算法基础14 —— 图论入门之迪杰斯特拉算法(Dijkstra)

    回顾 Floyed算法可以求任意两点之间的最短路径 但是Dijkstra算法只能求一个结点到另一个结点的最短路径 它是一个单源的最短路径算法 Floyed算法的时间复杂度为O n 3 故一般情况下数据范围要求在100以内 Dijkstra算