Dijkstra求最短路(图解)

你好,我是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,没有找到;否则输出最短路nif(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;}@Overridepublic 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.mzph.cn/news/105886.shtml

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

相关文章

Windows 中环境变量的查看与设置

接触了LLM应用开发后&#xff0c;经常要用到环境变量的设置&#xff08;openAI apikey啥的&#xff09; 但是老忘记&#xff0c;今天来学习和总结一下 主要用到以下几种&#xff1a;使用 PowerShell、CMD 和 Python 来查看和设置环境变量 文章目录 1. PowerShell查看环境变量&a…

【Linux】HTTP协议

文章目录 &#x1f4d6; 前言1. 认识URL && 引入http协议2. http协议格式2.1 宏观格式&#xff1a;2.2 实验演示&#xff1a; 3. http的方法3.1 GET方法&#xff1a;3.2 POST方法&#xff1a;3.3 GET vs POST&#xff1a; 4. HTTP的报头和状态码5. http的cookie5.1 htt…

估算总体标准差的极差均值估计法sigma = R/d2

总体标准差的估算值可以通过将平均极差除以合适的常数因子d2来计算。这个估算方法是用于估算总体标准差的一种常见方法&#xff0c;尤其在质量控制和过程监控中经常使用。 总体标准差的估算值 (平均极差) / d2 其中&#xff1a; "总体标准差的估算值" 表示用极差…

Floorplanning with Graph Attention

Floorplanning with Graph Attention DAC ’22 目录 Floorplanning with Graph Attention摘要1.简介2.相关工作3.问题公式化4. FLORA的方法4.1 解决方案概述4.2 C-谱聚类算法 4.3 基于GAT的模型4.4 合成训练数据集生成 摘要 布图规划一直是一个关键的物理设计任务&#xff0…

宝塔面板部署express以及MySql项目

第一次在宝塔面板上部署express和MySql项目&#xff0c;部署过程一直跑不通接口&#xff0c;特此记录一下。 在部署的时候&#xff0c;建议第一步把数据库MySql给跑通&#xff0c;中间好多原因是由于数据库的原因给引起的。 一.连接数据库 &#xff08;1&#xff09;在宝塔面…

深入promise

深入promise 我们可能知道如何使用 Promise&#xff0c;但是我们知道它们实际上是如何工作的吗&#xff1f; 为了让每个人都了解Promise&#xff0c;让我们从基础开始。如果我们知道 Promise 是什么以及如何使用它&#xff0c;我们可以跳过这一部分并直接跳到“魔法开始”的地…

RSA加密与解密原理

目录 一、什么是RSA加密 二、RSA加密原理 三、RSA加解密过程与算法代码 一、什么是RSA加密 RSA加密是一种非对称加密算法。 对称加密&#xff1a; 对称加密是一种加密方式&#xff0c;加密和解密使用同一个密钥&#xff0c;被加密的信息在传输前用预先协商好的密钥进行加密…

KUKA机器人如何强制输出或取消数字IO信号?

KUKA机器人如何强制输出或取消数字IO信号? 具体的操作方法和步骤可参考以下内容: 如下图所示,点击菜单—显示—输入/输出端,如下图所示,选择想要查看的信号,这里以数字输出端为例进行说明, 如下图所示,此时可以看到输出端信号的编号、名称和当前值,可以通过下拉滚动条…

河北专升本(C语言)

目录 一&#xff1a;C语言的构成特点 二: 数据类型 三: 常量、变量、运算符及表达式 &#xff08;一&#xff09;标识符 &#xff08;二&#xff09;常量 &#xff08;三&#xff09;变量&#xff1a;其值可以改变的量 &#xff08;四&#xff09;各种类型数据混合运算 &…

简单好用的解压缩软件:keka 中文 for mac

Keka是一款功能全面、易于使用的文件压缩和解压缩软件&#xff0c;为Mac用户提供了便捷的文件管理工具。它支持多种压缩格式&#xff0c;具有快速解压和强大的压缩功能&#xff0c;让您能够轻松地处理各种文件压缩需求。 隐私非常重要 安全共享只需设置密码并创建高度加密的文…

深度强化学习 第 2 章 蒙特卡洛

2.1随机变量 强化学习中会经常用到两个概念&#xff1a; 随机变量、 观测值。 本书用大写字母表示随机变量&#xff0c;小写字母表示观测值&#xff0c;避免造成混淆。 下面我们定义概率质量函数&#xff08;probability mass function&#xff0c;缩写 PMF&#xff09;和概率…

LINUX定时解压缩方案

需求背景 对接客户中某个上游为外包系统&#xff0c;外包系统每日推送压缩文件至指定文件夹下&#xff0c;文件格式为YYYYMMDD_RegReport.zip。由于每日采集文件&#xff0c;无法对接压缩包内文件&#xff0c;需要将推送的压缩文件每日解压为文件夹 需求分析 与客户沟通后&a…

HarmonyOS 远端状态订阅开发实例

IPC/RPC 提供对远端 Stub 对象状态的订阅机制&#xff0c; 在远端 Stub 对象消亡时&#xff0c;可触发消亡通知告诉本地 Proxy 对象。这种状态通知订阅需要调用特定接口完成&#xff0c;当不再需要订阅时也需要调用特定接口取消。使用这种订阅机制的用户&#xff0c;需要实现消…

C++初阶(1)

W...Y的主页&#x1f60a; 代码仓库分享&#x1f495; ​ &#x1f354;前言&#xff1a; 今天我们正式进入C篇章&#xff0c;作为学过C语言的同志&#xff0c;继续学习C肯定就不会进行那些与C语言相同的学习&#xff0c;因为C语言的内容在C中也可以正常使用&#xff0c;所…

通过示例详细了解ES6导入导出模块

通过示例详细了解ES6导入导出模块 似乎许多开发人员认为 ES6 模块只不过是export、import关键字。事实上&#xff0c;它更加多样化。它拥有强大的功能和鲜为人知的问题。在本文中&#xff0c;我们将使用一些示例来了解这些内容。 示例一 // index.mjs import { default } fr…

flask vue跨域问题

问题&#xff1a; 调试时候跨域访问报&#xff1a; Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response. 解决办法&#xff1a; 安装flask_cros from flask_cors import CORS CORS(app) app.after_request def a…

如何避免大语言模型绕过知识库乱答的情况?LlamaIndex 原理与应用简介

本文首发于博客 LLM 应用开发实践 随着 LangChain LLM 方案快速普及&#xff0c;知识问答类应用的开发变得容易&#xff0c;但是面对回答准确度要求较高的场景&#xff0c;则暴露出一些局限性&#xff0c;比如向量查询方式得到的内容不匹配&#xff0c;LLM 对意图识别不准。所…

【Linux】多线程

文章目录 一.Linux线程概念1.什么是线程2.二级页表3.线程的优点4.线程的缺点5.线程异常6.线程用途 二.Linux进程VS线程1.进程和线程2.进程的多个线程共享3.进程和线程的关系 三.Linux线程控制1.POSIX线程库2.线程创建3.线程等待4.线程终止5.分离线程6.线程ID及进程地址空间布局…

手机拍摄的视频噪点很多怎么办,视频怎么做降噪处理?

现如今&#xff0c;智能手机已经成为了我们生活中必不可少的存在。而随着智能手机越来越强大&#xff0c;很多人已经开始使用手机来拍摄各种类型的视频。但是由于手机的限制&#xff0c;很多人会发现自己拍摄的视频存在着很多的噪点。那么&#xff0c;我们该怎样来解决拍摄视频…

N点复序列求2个N点实序列的快速傅里叶变换

一、方法简介 通过一个点复数序列求出两个点实数序列的离散傅里叶变换&#xff0c;进一步提升快速傅里叶变换的效率。 二、方法详解 和是实数序列&#xff0c;且长度都为&#xff0c;定义复数序列&#xff1a; &#xff0c; 则序列和可表示为&#xff1a; 的离散傅…