Dijkstra求最短路(图解)

news2024/10/6 4:11:55

你好,我是Hasity。

今天分享的内容:Dijkstra求最短路这个题目

Dijkstra求最短路I

题目描述

给定一个 n个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为正值。

请你求出 1 号点到 n号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1。

输入格式

第一行包含整数 n 和 m。

接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。

输出格式

输出一个整数,表示 1 号点到 n号点的最短距离。

如果路径不存在,则输出 −1。

数据范围

1≤n≤500,
1≤m≤105,
图中涉及边长均不超过10000。

示例:

思路分析

迪杰斯特拉算法采用的是一种贪心的策略。求源点到其余各点的最短距离步骤如下:

  1. 用一个 dist 数组保存源点到其余各个节点的距离,dist[i] 表示源点到节点 i 的距离。初始时,dist 数组的各个元素为无穷大。
    用一个状态数组 state 记录是否找到了源点到该节点的最短距离,state[i] 如果为真,则表示找到了源点到节点 i 的最短距离,state[i] 如果为假,则表示源点到节点 i 的最短距离还没有找到。初始时,state 各个元素为假。

03.png

  1. 源点到源点的距离为 0。即dist[1] = 0。04.png

  2. 遍历 dist 数组,找到一个节点,这个节点是:没有确定最短路径的节点中距离源点最近的点。假设该节点编号为 i。此时就找到了源点到该节点的最短距离,state[i] 置为 1。05.png

  3. 遍历 i 所有可以到达的节点 j,如果 dist[j] 大于 dist[i] 加上 i -> j 的距离,即 dist[j] > dist[i] + w[i][j](w[i][j] 为 i -> j 的距离) ,则更新 dist[j] = dist[i] + w[i][j]。

06.png

  1. 重复 3 4 步骤,直到所有节点的状态都被置为 1。
  • 更新与序号1相连接的节点(2,3,4)的dist,离源点1距离最近的状态为0的节点是2,将节点2的state改为1,更新与序号2相连接的节点5的dist

  • 离源点1距离最近的状态为0的的节点是4,将节点4的state改为1,更新与序号4相连接的节点5的dist

  • 离源点1距离最近的状态为0的的节点是3,将节点3的state改为1,更新与序号3相连接的节点4的dist

  • 离源点1距离最近的状态为0的的节点是5,将节点5的state改为1,更新与序号5相连接的节点的的dist(没有也需要遍历一遍)

071.png

  1. 此时 dist 数组中,就保存了源点到其余各个节点的最短距离。

13.png

思考:我们用什么数据结构表示图的任意顶点之间的连接关系呢?

邻接表和邻接矩阵是图的两种常用存储表示方式,用于记录图中任意两个顶点之间的连通关系,包括权值。

对于无向图 graph和有向图digraph

graph

digraph

  • 选择一:邻接表

无向图 graph 表示

graph_adjacency_list

有向图 digraph 表示

digraph_adjacency_list

  • 选择二:邻接矩阵

无向图 graph 表示

graph_adjacency_matrix

有向图 digraph 表示

digraph_adjacency_matrix

由题中的1≤n≤500的数据量较小,我们采用邻接矩阵的方法代码更容易实现

关于领接表的优缺点:大家可以看这一篇文章:

代码实现
import java.util.*;
public class Main{
    static int N = 510,n,m, max = 0x3f3f3f3f;
    static int[][] g = new int[N][N];//存每个点之间的距离
    static int[] dist = new int[N];//存每个点到起点之间的距离
    static boolean[] st = new boolean[N];//存已经确定了最短距离的点
    public static int dijkstra(){
        Arrays.fill(dist,max);//将dist数组一开始赋值成较大的数
        dist[1] = 0; //首先第一个点是零

        //从0开始,遍历n次,一次可以确定一个最小值
        for(int i = 0 ; i < n ; i ++ ){ 
            int t = -1; //t这个变量,准备来说就是转折用的
            for(int j = 1 ; j <= n ; j ++ ){
                /***
                 * 因为数字是大于1的,所以从1开始遍历寻找每个数
                 * 如果s集合中没有这个数
                 * 并且t == -1,表示刚开始 或者 后面的数比我心找的数距离起点的距离短
                 * 然后将j 的值赋值给 t
                 ***/
                if(!st[j] && (t == -1 || dist[j] < dist[t])){
                    t = j; 
                }
            }

            st[t] = true;//表示这个数是已经找到了确定了最短距离的点

            //用已经确认的最短距离的点来更新后面的点
            //就是用1到t的距离加上t到j的距离来更新从1到j的长度
            for(int j = 1 ; j <= n ; j ++ ){
                //
                dist[j] = Math.min(dist[j],dist[t] + g[t][j]);
            }
        }
        //如果最后n的长度没有改变,输出-1,没有找到;否则输出最短路n
        if(dist[n] == max) return -1;
        else return dist[n];

    }
    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        //将他们每个点一开始赋值成一个较大的值
        for(int i = 1 ; i <= n ; i ++ ){
            Arrays.fill(g[i],max);
        }
        while(m -- > 0){
            int a = scan.nextInt();
            int b = scan.nextInt();
            int c = scan.nextInt();
            g[a][b] = Math.min(g[a][b],c);//这个因为可能存在重边,所以泽出最短的
        }
        int res = dijkstra();
        System.out.println(res);
    }
}
Dijkstra求最短路 II

题目描述

给定一个 n个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为正值。

请你求出 1 号点到 n号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1。

输入格式

第一行包含整数 n 和 m。

接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。

输出格式

输出一个整数,表示 1 号点到 n号点的最短距离。

如果路径不存在,则输出 −1。

数据范围

1≤n,m≤1.5×105
图中涉及边长均不小于 0,且不超过 10000。
数据保证:如果最短路存在,则最短路的长度不超过 109

示例:

思路分析

这道题和上一道没有什么区别,差别只有数据范围的变化

第一题:

1≤n≤500,
1≤m≤105,
图中涉及边长均不超过10000。

第二题:

1≤n,m≤1.5×105
图中涉及边长均不小于 0,且不超过 10000。
数据保证:如果最短路存在,则最短路的长度不超过 109

我们可以对比发现,节点n的取值变大了,那么按照之前的时间复杂度O(n2)是肯定会超时的,所以我们需要降低时间复杂度,使用优先队列(小根堆)解决,并且随着n的取值变大,我们使用领接表来替代邻接矩阵存储图之间的关系

第一题:找到未标记的离源点最近的点 O(n2)

   for(int i = 0 ; i < n ; i ++ ){ 
            int t = -1; //t这个变量,准备来说就是转折用的
            for(int j = 1 ; j <= n ; j ++ ){
                /***
                 * 因为数字是大于1的,所以从1开始遍历寻找每个数
                 * 如果s集合中没有这个数
                 * 并且t == -1,表示刚开始 或者 后面的数比我心找的数距离起点的距离短
                 * 然后将j 的值赋值给 t
                 ***/
                if(!st[j] && (t == -1 || dist[j] < dist[t])){
                    t = j; 
                }
            }
            

算法的主要耗时的步骤是从dist 数组中选出:没有确定最短路径的节点中距离源点最近的点 t。只是找个最小值而已,没有必要每次遍历一遍dist数组。在一组数中每次能很快的找到最小值,很容易想到使用优先队列(小根堆)

image-20231014184356158

55fec2d8dd5e91cdc6f8b5d179a7d19.png

代码实现
import java.util.*;
class PIIs implements Comparable<PIIs>{
    private int first;//距离值
    private int second;//点编号

    public int getFirst()
    {
        return this.first;
    }
    public int getSecond()
    {
        return this.second;
    }
    public PIIs(int first,int second)
    {
        this.first = first;
        this.second = second;
    }
    @Override
    public int compareTo(PIIs o) {
        // TODO 自动生成的方法存根
        return Integer.compare(first, o.first);
    }
}
public class Main{
    static int N = 150010,n,m,idx,max = 0x3f3f3f3f;
    static int [] h = new int[N],e = new int[N],ne = new int[N],w = new int[N];
    static int[] dist = new int[N];
    static boolean[] st = new boolean[N];
    public static void add(int a,int b,int c){
        e[idx] = b;
        w[idx] = c;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    public static int dijkstra()
    {
        //优先队列,保证每次取出都是最小值
        //维护当前未在st中标记过且离源点最近的点   小跟堆
        PriorityQueue<PIIs> queue = new PriorityQueue<PIIs>();
        Arrays.fill(dist, max);
        dist[1] = 0;
        queue.add(new PIIs(0,1));
        while(!queue.isEmpty())
        {
            //1、找到当前未在s中出现过且离源点最近的点
            PIIs p = queue.poll();
            int distance = p.getFirst();
            int t = p.getSecond();
            if(st[t]) continue;
            //2、将该点进行标记
            st[t] = true;
            //3、用t更新其他点的距离
            for(int i = h[t];i != -1;i = ne[i])//不要被这个遍历误导,这只是一个遍历循环而已,i只是下一个点的下标
            {
                int j = e[i];// i只是个下标,e中在存的是i这个下标对应的点和值。
                if(dist[j] > distance + w[i])
                {
                    dist[j] = distance + w[i];
                    queue.add(new PIIs(dist[j],j));
                }
            }

        }
        if(dist[n] == max) return -1;
        return dist[n];
    }

    public static void main(String[] args){
        Scanner scan = new Scanner(System.in);
        n = scan.nextInt();
        m = scan.nextInt();
        Arrays.fill(h,-1);
        while(m -- > 0){
            int a = scan.nextInt();
            int b = scan.nextInt();
            int c = scan.nextInt();
            add(a,b,c);
        }
        int res = dijkstra();
        System.out.println(res);
    }
}

总结

迪杰斯特拉算法适用于求正权有向图中,源点到其余各个节点的最短路径。注意:图中可以有环,但不能有负权边。

例如:如下图就不能使用迪杰斯特拉算法求节点 1 到其余各个节点的最短距离。

14.png

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

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

相关文章

关于导入Maven工程项目,更新pom.xml文件仍然爆红的原因

问题描述&#xff1a; 在学习maven工程的时候&#xff0c;把从网上学习的工程导入到IDEA&#xff0c;发现&#xff0c;无论怎么更新&#xff0c;pom.xml文件一直报错&#xff0c;查看settings设置和project Structure仍然没找出问题来。 settings设置如下&#xff1a; 解决问…

短视频如何批量添加水印

在当今的数字时代&#xff0c;短视频已经成为一种非常流行的内容形式。无论是社交媒体还是视频分享网站&#xff0c;短视频都已经成为了一种非常有吸引力的内容。然而&#xff0c;对于一些拥有大量视频内容的创作者来说&#xff0c;添加水印可能是一项繁琐的任务。本文将介绍如…

【windows下docker安装rocketMQ】

namesrv和broker安装就不说了&#xff0c;见如下博客 https://blog.csdn.net/Wonderful1025/article/details/107244434/ 安装rocketMQ-console docker run -d -e "JAVA_OPTS-Drocketmq.config.namesrvAddr192.168.65.2:9876 -Drocketmq.config.isVIPChannelfalse"…

__builtin_return_address()函数的使用方法

__builtin_return_address(0) 是GCC编译器提供的内置函数&#xff0c;用于获取当前函数调用栈中的指定帧&#xff08;frame&#xff09;的返回地址。这个函数通常用于调试和性能分析&#xff0c;以了解程序中的函数调用关系。 下面是关于 __builtin_return_address(0) 函数的一…

SystemC入门学习-第5章 同步逻辑建模

本章重点学习同步逻辑中的触发器&#xff0c;锁存器的一些建模规范&#xff1a; 触发器建模带异步置位/复位带同步置位/复位锁存器建模 5.1 触发器建模 触发器建模的关键是敏感列表的规范。SC_MODULE的规范写法中出现过sensitive 参数列表是事件敏感&#xff0c; 对触发器建模…

操作系统学习笔记4-死锁问题

文章目录 1、死锁逻辑图2、死锁三胞胎3、死锁的原因及必要条件4、死锁处理策略之死锁预防5、死锁处理策略之死锁避免&#xff08;银行家算法&#xff09;6、死锁处理策略之死锁检测与解除 1、死锁逻辑图 2、死锁三胞胎 3、死锁的原因及必要条件 4、死锁处理策略之死锁预防 5、死…

查找组成一个偶数最接近的两个素数

一、题目 二、代码 #include <iostream> using namespace std; bool isPrime(int num)//判断素数 {if (num < 1)return false;if (num 2)return true;if (num % 2 0)return false;for (int i 3; i < num; i){if (num % i 0){return false;}}return true; } in…

win11下的VS2022+QT6+VTK9.2+PCL1.13.1联合开发环境配置及踩坑记录

准备工作&#xff1a; 安装VS2022&#xff1a;这个比较简单&#xff0c;网上随便找个教程就行 安装QT并为VS2022添加QT Creater插件&#xff1a;VS2022配置Qt6_vs2022 qt6-CSDN博客 安装PCL&#xff1a;vs2022配置pcl1.13.1_pcl配置-CSDN博客 安装PCL过程中本身也会安装VTK&…

小程序入门及案例展示

目录 一、小程序简介 1.1 为什么要使用小程序 1.2 小程序可以干什么 二、前期准备 2.1 申请账号 2.2 开发工具下载与安装 三、电商案例演示 四、入门案例 4.1 项目结构解析 4.2 基础操作及语法 4.3 模拟器 4.4 案例演示 4.4.1 新建页面 4.4.2 头部样式设置 4.4.…

Marin说PCB之CoilcraftBourns POC 电感的性能对比

十一小长假本来是一件美好事情。可是天有不测风云&#xff0c;小编我却有祸兮来了。本来是公司的硬件同事强哥要回以色列了&#xff0c;最近他们国家那边都在打仗&#xff0c;强哥本着舍身为国的精神回国抗战去了。小编我就想着在他回国之前搞了篮球比赛送别一下他呢&#xff0…

小程序入门——详细教程

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 生活的理想&#xff0c;为了不断更新自己 ! 1.微信小程序 入门 1.1什么是小程序&#xff1f; 2017年度百度百科十大热词之一 微信小程…

BUUCTF pwn1_sctf_2016 1

代码分析 查看文件信息然后进行反汇编 关键信息 32位栈不可执行 IDA反汇编 说实话&#xff0c;这个应该是C编写的程序&#xff0c;C基础还是不行&#xff0c;我硬是没看懂这个代码 我查了一下字符串 这里的get_flag是函数&#xff0c;另一个应该就是执行的一个命令了 到IDA…

【LeetCode刷题(数据结构)】:翻转二叉树

方法一&#xff1a;递归 思路与算法 这是一道很经典的二叉树问题。显然&#xff0c;我们从根节点开始&#xff0c;递归地对树进行遍历&#xff0c;并从叶子节点先开始翻转。如果当前遍历到的节点 root\textit{root}root 的左右两棵子树都已经翻转&#xff0c;那么我们只需要交…

【入门】.Net Core 6 WebApi 项目搭建

一、创建项目 1.1.创建新项目&#xff1a;打开开发工具>创建新项目>搜索API>选择C#语言的ASP.NET Core Web API 1.2.配置新项目&#xff1a;**自定义项目信息以及存储路径 1.3.其他信息&#xff1a;这里框架必须选择.NET 6.0,其他配置默认勾选即可&#xff0c;也可以根…

SystemVerilog Assertions应用指南 第一章(1.24章节 “or”运算符)

二进制运算符“or”可以用来逻辑地组合两个序列。只要其中一个序列成功,整个属性就成功。序列s29a和s29b是两个独立的序列。属性p29将两者用“or运算符组合起来。当其中任一序列成功时,属性就成功。 sequence s29a;(posedge clk) a##[1:2] b; endsequencesequence s29b;(posed…

Hadoop3教程(六):HDFS中的DataNode

文章目录 &#xff08;63&#xff09;DataNode工作机制&#xff08;64&#xff09;数据完整性&#xff08;65&#xff09;掉线时限参数设置参考文献 &#xff08;63&#xff09;DataNode工作机制 DataNode内部存储了一个又一个Block&#xff0c;每个block由数据和数据元数据组…

2024年计算机专业Java选题推荐✅(最新、最全、最容易通过的选择)

文章目录 前言选题和具体实现详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&#x…

USDR脱锚事件:稳定币碰上房地产,双重buff想不崩都难!

10月11日&#xff0c;一种名为Real USD&#xff08;USDR&#xff09;的稳定币脱锚&#xff0c;在几个小时内迅速从1美元跌至0.5美元&#xff0c;而这无疑是一场典型的挤兑&#xff0c;主要由该稳定币的高流动性债务与其低流动性抵押物之间存在期限错配所致。 USDR是一种流通量为…

链表oj (7.29)

203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 思路1&#xff1a;使用结构体指针 cur 遍历链表&#xff0c;遇到值为 val 时删除&#xff0c;删除之前需要判断是头删还是正常的删除&#xff0c;头删需要改变头指针&#xff1b; 正常的删除需要 cur(待删除节点&am…

爬虫 | 基础模块了解

文章目录 &#x1f4da;http协议&#x1f4da;requests模块&#x1f4da;re模块&#x1f407; re.I 或 re.IGNORECASE&#x1f407;re.M或 re.MULTILINE&#x1f407;re.S 或 re.DOTALL&#x1f407; re.A 或 re.ASCII&#x1f407; re.X 或 re.VERBOSE&#x1f407;特殊字符类…