Dijkstra 算法代码步骤[leetcode.743网络延迟时间]

有 n 个网络节点,标记为 1 到 n

给你一个列表 times,表示信号经过 有向 边的传递时间。 times[i] = (ui, vi, wi),其中 ui 是源节点,vi 是目标节点, wi 是一个信号从源节点传递到目标节点的时间。

现在,从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1 。

示例 1:

输入:times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
输出:2

算法流程

  1. 初始化

    • 邻接矩阵 g 存储边权。

    • dis 数组存储源点到各点的最短距离,初始为 INF

    • done 数组标记节点是否已确定最短路径。

  2. Dijkstra 主循环

    • 选择当前未处理的、距离最短的节点 x

    • 如果 x 不可达,返回 -1

    • 更新 maxDis 为 dis[x](因为 dis[x] 是递增的)。

    • 标记 x 为已处理。

    • 松弛 x 的所有邻居 y,更新 dis[y]

  3. 终止条件

    • 所有节点已处理,返回 maxDis(最长延迟时间)。

时间复杂度

  • 邻接矩阵实现O(n^2)(适用于稠密图)。

  • 堆优化(优先队列)O(E log V)(适用于稀疏图,但本题未使用)。

空间复杂度

  • O(n^2)(邻接矩阵存储)。

1. 初始化

final int INF = Integer.MAX_VALUE / 2; // 防止加法溢出
int[][] g = new int[n][n]; // 邻接矩阵
for (int[] row : g) {Arrays.fill(row, INF);
}
  • INF:表示“无穷大”,用于初始化不可达的边。Integer.MAX_VALUE / 2 是为了防止后续计算 dis[x] + g[x][y] 时溢出。

  • g:邻接矩阵,g[i][j] 表示从节点 i 到 j 的传输时间(权重)。

  • 初始化邻接矩阵:所有边初始为 INF(表示初始时所有节点之间不可达)。


2. 构建图的邻接矩阵

for (int[] t : times) {g[t[0] - 1][t[1] - 1] = t[2];
}
  • times 是一个二维数组,其中 times[i] = [u, v, w] 表示从节点 u 到 v 的传输时间为 w

  • 存储到邻接矩阵

    • g[t[0] - 1][t[1] - 1] = t[2]:因为节点编号从 1 开始,而数组索引从 0 开始,所以需要 -1 调整。


3. Dijkstra 算法初始化

int maxDis = 0;
int[] dis = new int[n];
Arrays.fill(dis, INF);
dis[k - 1] = 0;
boolean[] done = new boolean[n];
  • maxDis:记录所有最短路径中的最大值(即网络延迟时间)。

  • disdis[i] 表示从源节点 k 到节点 i 的最短距离,初始为 INF(不可达)。

  • dis[k - 1] = 0:源节点到自身的距离为 0

  • done:标记节点是否已经确定最短路径。


4. Dijkstra 主循环

while (true) {int x = -1;for (int i = 0; i < n; i++) {if (!done[i] && (x < 0 || dis[i] < dis[x])) {x = i;}}if (x < 0) {return maxDis; // 所有节点已处理完毕}if (dis[x] == INF) { // 有节点无法到达return -1;}maxDis = dis[x]; // 更新最大延迟时间done[x] = true; // 标记 x 的最短路径已确定for (int y = 0; y < n; y++) {dis[y] = Math.min(dis[y], dis[x] + g[x][y]);}
}

(1) 选择当前未处理的最短路径节点

int x = -1;
for (int i = 0; i < n; i++) {if (!done[i] && (x < 0 || dis[i] < dis[x])) {x = i;}
}
  • x:当前未处理(!done[i])且距离 dis[i] 最小的节点。

  • 贪心策略:每次选择距离源节点最近的未处理节点进行扩展。

(2) 检查是否所有节点已处理

if (x < 0) {return maxDis; // 所有节点已处理完毕
}
  • x < 0:表示所有节点都已处理,返回 maxDis(即最长延迟时间)。

(3) 检查是否有节点不可达

if (dis[x] == INF) { // 有节点无法到达return -1;
}
  • dis[x] == INF:表示当前节点 x 无法从源节点到达,直接返回 -1

(4) 更新 maxDis 并标记 x 为已处理

maxDis = dis[x]; // 更新最大延迟时间
done[x] = true; // 标记 x 的最短路径已确定
  • maxDis:由于 Dijkstra 每次处理的 dis[x] 是递增的,所以直接更新即可。

  • done[x] = true:表示 x 的最短路径已确定,后续不再更新。

(5) 松弛操作(更新邻居的最短距离)

for (int y = 0; y < n; y++) {dis[y] = Math.min(dis[y], dis[x] + g[x][y]);
}
  • 松弛(Relaxation):尝试通过 x 缩短 y 的最短路径:

    • 如果 dis[x] + g[x][y] < dis[y],则更新 dis[y]

完整版代码:

class Solution {public int networkDelayTime(int[][] times, int n, int k) {final int INF = Integer.MAX_VALUE / 2; // 防止加法溢出int[][] g = new int[n][n]; // 邻接矩阵for (int[] row : g) {Arrays.fill(row, INF);}for (int[] t : times) {g[t[0] - 1][t[1] - 1] = t[2];}int maxDis = 0;int[] dis = new int[n];Arrays.fill(dis, INF);dis[k - 1] = 0;boolean[] done = new boolean[n];while (true) {int x = -1;for (int i = 0; i < n; i++) {if (!done[i] && (x < 0 || dis[i] < dis[x])) {x = i;}}if (x < 0) {return maxDis; // 最后一次算出的最短路就是最大的}if (dis[x] == INF) { // 有节点无法到达return -1;}maxDis = dis[x]; // 求出的最短路会越来越大done[x] = true; // 最短路长度已确定(无法变得更小)for (int y = 0; y < n; y++) {// 更新 x 的邻居的最短路dis[y] = Math.min(dis[y], dis[x] + g[x][y]);}}}
}

 

示例

输入

times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2

执行流程

  1. 初始化

    • dis = [INF, 0, INF, INF](源节点 k=2 的距离为 0)。

  2. 第一次循环

    • 选择 x=1dis[1] = 0)。

    • 松弛邻居 y=0 和 y=2

      • dis[0] = min(INF, 0 + 1) = 1

      • dis[2] = min(INF, 0 + 1) = 1

    • maxDis = 0

  3. 第二次循环

    • 选择 x=0 或 x=2dis[0] = 1dis[2] = 1)。

    • 假设选 x=0,但没有邻居可更新。

    • maxDis = 1

  4. 第三次循环

    • 选择 x=2

    • 松弛邻居 y=3

      • dis[3] = min(INF, 1 + 1) = 2

    • maxDis = 1

  5. 第四次循环

    • 选择 x=3

    • 没有邻居可更新。

    • maxDis = 2

  6. 结束

    • 所有节点已处理,返回 maxDis = 2

最终输出2(最长延迟时间)。

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

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

相关文章

【java】lambda表达式总结

目录 一、面向对象的处理方法 二、函数式编程的处理方法 先使用匿名内部类&#xff1a; lambda改造&#xff1a; lambda改造规则 示例&#xff1a; 三、补充&#xff1a;函数式接口 大家好&#xff0c;我是jstart千语。今天总结一下lambda表达式。lambda表达式在后面的s…

AtCoder Beginner Contest 242 G - Range Pairing Query (莫队)

每周五篇博客&#xff1a;&#xff08;5/5&#xff09; 我做到了&#xff01; https://atcoder.jp/contests/abc242/tasks/abc242_g 这题主要是想给大家提供一份莫队的板子&#xff0c;很多莫队题基本上填空就差不多了&#xff08; 板子 void solve() {int n;std::cin >…

淘宝商品主图标题api接口

1、输入淘宝商品id或者链接&#xff0c;点查询 2、查询淘宝商品主图&#xff0c;商品标题&#xff0c;商品价格&#xff0c;卖家旺旺 3、支持api接口

文心一言开发指南06——千帆大模型平台新手指南

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 千帆大模型平台为新手用户提供了一个全面的入门指南&#xff0c;以便用户能够快速熟悉平台的操作和功能。千帆大模型平台通过提供详细的新手指南&#xff0c;确保用户能够顺…

Pacman-N-queen

文档 代码及文档&#xff1a;通过网盘分享的文件&#xff1a;code 链接: https://pan.baidu.com/s/1Rgo9ynnEqjZsSP2-6TyS8Q?pwdn99p 提取码: n99p 补充核心代码 核心代码内容&#xff1a; genetic_algorithm,py # -*- coding: utf-8 -*- """ Created on …

常用的多传感器数据融合方法

1. 概述 根据具体需求&#xff08;实时性、计算资源、噪声特性&#xff09;选择合适的方法&#xff0c;实际应用中常结合多种方法&#xff08;如UKF与神经网络结合&#xff09;。 传统方法 &#xff08;KF/EKF/UKF/PF&#xff09;依赖数学模型&#xff0c;适合动态系统&#…

简单几步,开启 Intel VT-x 让电脑“解开CPU封印”

#vmware #虚拟机 #cpu虚拟化 # Intel VT-x 前言 你是不是也遇到过这种情况&#xff1a;在尝试运行虚拟机&#xff08;VM&#xff09;、安卓模拟器&#xff0c;或者使用 Windows 沙盒、WSL2 等功能时&#xff0c;遇到了类似“此主机支持 Intel VT-x&#xff0c;但 Intel VT-x …

Go语言--语法基础4--基本数据类型--字符串类型

在 Go 语言中&#xff0c;字符串也是一种基本类型。相比之下&#xff0c; C/C 语言中并不存在原 生的字符串类型&#xff0c; 通常使用字符数组来表示&#xff0c;并以字符指针来传递。 Go 语言中字符串的声明和初始化非常简单&#xff0c;举例如下&#xff1a; var str st…

QT中的事件及其属性

Qt中的事件是对操作系统提供的事件机制进行封装&#xff0c;Qt中的信号槽就是对事件机制的进一步封装 但是特殊情况下&#xff0c;如对于没有提供信号的用户操作&#xff0c;就需要通过重写事件处理的形式&#xff0c;来手动处理事件的响应逻辑 常见的Qt事件&#xff1a; 常见事…

socket套接字-UDP(中)

socket套接字-UDP&#xff08;上&#xff09;https://blog.csdn.net/Small_entreprene/article/details/147465441?fromshareblogdetail&sharetypeblogdetail&sharerId147465441&sharereferPC&sharesourceSmall_entreprene&sharefromfrom_link UDP服务器…

C++入门小馆: STL 之queue和stack

嘿&#xff0c;各位技术潮人&#xff01;好久不见甚是想念。生活就像一场奇妙冒险&#xff0c;而编程就是那把超酷的万能钥匙。此刻&#xff0c;阳光洒在键盘上&#xff0c;灵感在指尖跳跃&#xff0c;让我们抛开一切束缚&#xff0c;给平淡日子加点料&#xff0c;注入满满的pa…

ALTER TABLE 删除DROP表列的报错: 因为有一个或多个对象访问此列

目录 1.问题 2.解决办法 1.问题 删除某个列名的时候&#xff0c;提示错误因为有一个或多个对象访问此列 2.解决办法 2.1 添加或删除表新列名 将表中的字段设置Default 或 NOT NULL 都会给该字段添加约束&#xff0c;增加了这些约束后&#xff0c;再SQL脚本修改类型、删除会发生…

python源码打包为可执行的exe文件

文章目录 简单的方式&#xff08;PyInstaller&#xff09;特点步骤安装 PyInstaller打包脚本得到.exe文件 简单的方式&#xff08;PyInstaller&#xff09; 特点 支持 Python 3.6打包为单文件&#xff08;–onefile&#xff09;或文件夹形式自动处理依赖项 步骤 安装 PyIns…

【2025最近Java面试八股】Spring中循环依赖的问题?怎么解决的?

1. 什么是循环依赖&#xff1f; 在Spring框架中&#xff0c;循环依赖是指两个或多个bean之间相互依赖&#xff0c;形成了一个循环引用的情况。如果不加以处理&#xff0c;这种情况会导致应用程序启动失败。导致 Spring 容器无法完成依赖注入。 例如&#xff1a; Service publi…

JimuBI 积木报表 v1.9.5发布,大屏和仪表盘,免费数据可视化

项目介绍 JimuBI (积木报表BI) 是一款免费的数据可视化产品&#xff0c;含大屏和仪表盘、门户、移动图表&#xff0c;像搭建积木一样完全在线设计&#xff01; 大屏采用类word风格&#xff0c;可以随意拖动组件&#xff0c;想怎么设计怎么设计&#xff0c;可以像百度和阿里一样…

云原生课程-Docker

一次镜像&#xff0c;到处运行。 1. Docker详解&#xff1a; 1.1 Docker简介&#xff1a; Docker是一个开源的容器化平台&#xff0c;可以帮助开发者将应用程序和其依赖的环境打包成一个可移植的&#xff0c;可部署的容器。 docker daemon:是一个运行在宿主机&#xff08;DO…

HikariCP 6.3.0 完整配置与 Keepalive 优化指南

HikariCP 6.3.0 完整配置与 Keepalive 优化指南 HikariCP 是一个高性能、轻量级的 JDBC 连接池框架&#xff0c;广泛应用于 Java 应用&#xff0c;尤其是 Spring Boot 项目。本文档基于 HikariCP 6.3.0 版本&#xff0c;详细介绍其功能、配置参数、Keepalive 机制以及优化建议…

基于springboot+vue的摄影师分享交流社区的设计与实现

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

ComfyUI for Windwos与 Stable Diffusion WebUI 模型共享修复

#工作记录 虽然在安装ComfyUI for Windwos时已经配置过extra_model_paths.yaml 文件&#xff0c;但升级ComfyUI for Windwos到最新版本后发现原先的模型配置失效了&#xff0c;排查后发现&#xff0c;原来是 extra_model_paths.yaml 文件在新版本中被移动到了C盘目录下&#x…

【最新版】沃德代驾源码全开源+前端uniapp

一.系统介绍 基于ThinkPHPUniapp开发的代驾软件。系统源码全开源&#xff0c;代驾软件的主要功能包括预约代驾、在线抢单、一键定位、在线支付、车主登记和代驾司机实名登记等‌。用户可以通过小程序预约代驾服务&#xff0c;系统会估算代驾价格并推送附近代驾司机供用户选择&…