最短路径 | 743. 网络延迟时间之 Dijkstra 算法和 Floyd 算法

news2024/11/15 16:57:32

目录

    • 1 基于 Dijkstra 算法
      • 1.1 代码说明
      • 1.2 完整代码
    • 2 基于 Floyd 算法
      • 2.1 代码说明
      • 2.2 完整代码


前言:我在做「399. 除法求值」时,看到了基于 Floyd 算法的解决方案,突然想起来自己还没有做过最短路径相关的题。因此找来了「743. 网络延迟时间」作为练习,其本质是在求解一个源点到其他各点的最短路径。



1 基于 Dijkstra 算法

假设源点为 2 \mathrm{2} 2,那么手工模拟如下图所示:

在这里插入图片描述

代码的编写在本质上就是实现上述手工模拟过程。



1.1 代码说明

为了表示两点之间没有路径,我们定义两点之间的距离为无穷大:

const int inf = INT_MAX / 2;

说明:这里只是对 i n f \mathrm{inf} inf 进行定义,后面才会进行使用;为什么不直接定义为 i n f = I N T − M A X \mathrm{inf = INT_{-}MAX} inf=INTMAX?因为在更新距离时涉及加法操作,而 I N T − M A X \mathrm{INT_{-}MAX} INTMAX 可能让加法越界,所以我们取其一半来表示无穷大。

Step1:构建图

由于题目通常给出的是边的起点、终点以及权值,而非存储了图结构的二维数组,因此无论是 Dijkstra 算法还是 Floyd 算法,我们都需要完成图的构建。代码如下:

vector<vector<int>> graph(n + 1, vector<int>(n + 1, inf));
for (auto & t : times)
  graph[t[0]][t[1]] = t[2];

逻辑非常简单:① 创建一个二维数组 g r a p h \mathrm{graph} graph;② g r a p h [ i ] [ j ] \mathrm{graph[i][j]} graph[i][j] 表示边 < i , j > \mathrm{<i, j>} <i,j> 的权值。

说明:初始时如果两点之间没有边,那么认为两点之间的距离为 i n f \mathrm{inf} inf 无穷大。

Step2:定义数组

vector<int> dist(n + 1, inf);
dist[k] = 0;
vector<int> used(n + 1, 0);
  • d i s t \mathrm{dist} dist 数组用于存储每一轮源点 k \mathrm{k} k 到其他点的距离;
  • u s e d \mathrm{used} used 数组用于表明当前点是否已经被纳入集合。

说明:由于 k \mathrm{k} k 到自己的距离为 0 \mathrm{0} 0,因此有 d i s t [ k ] = 0 \mathrm{dist[k] = 0} dist[k]=0;为什么不直接让 u s e d [ k ] = 1 \mathrm{used[k] = 1} used[k]=1?由于在纳入每个点时都会更新源点 k \mathrm{k} k 到其他点的距离,因此我们在初始时并不直接将 k \mathrm{k} k 纳入集合,而是放到后面和其他点统一处理,从而避免了需要在初始时更新 d i s t \mathrm{dist} dist 数组的值的问题。

Step3:纳入并更新距离

for (int i = 1; i <= n; ++i) {
  // 查找距离源点最近的点
  int s = -1;
  for (int t = 1; t <= n; ++t) {
    if (!used[t] && (s == -1 || dist[s] > dist[t]))
      s = t;
  }
  // 纳入该点
  used[s] = 1;
  // 更新距离
  for (int j = 1; j <= n; ++j)
    dist[j] = min(dist[j], dist[s] + graph[s][j]);
}

其中 s \mathrm{s} s 用于查找当前距离源点最近的点, t \mathrm{t} t 用于遍历所有未被纳入的点。

说明:由于初始时只有 d i s t [ k ] = 0 \mathrm{dist[k] = 0} dist[k]=0,而其他距离被默认为 i n f \mathrm{inf} inf 无穷大,因此第一个被纳入的一定是源点 k \mathrm{k} k

Step4:返回结果

由于题目提问「需要多久才能使所有节点都收到信号」,因此我们返回源点 k \mathrm{k} k 到其他点的最短距离的最大值即可。代码如下:

int ans = * max_element(dist.begin() + 1, dist.end());
return ans == inf ? -1 : ans;

如果最大值是 i n f \mathrm{inf} inf,那么说明源点 k \mathrm{k} k 无法到达某些点,因此返回 − 1 \mathrm{-1} 1



1.2 完整代码

int networkDelayTime(vector<vector<int>>& times, int n, int k) {
  const int inf = INT_MAX / 2;
  vector<vector<int>> graph(n + 1, vector<int>(n + 1, inf));
  for (auto & t : times)
    graph[t[0]][t[1]] = t[2];

  vector<int> dist(n + 1, inf);
  dist[k] = 0;
  vector<int> used(n + 1, 0);

  for (int i = 1; i <= n; ++i) {
    int s = -1;
    for (int t = 1; t <= n; ++t) {
      if (!used[t] && (s == -1 || dist[s] > dist[t]))
        s = t;
    }
    used[s] = 1;
    for (int j = 1; j <= n; ++j)
      dist[j] = min(dist[j], dist[s] + graph[s][j]);
  }

  int ans = * max_element(dist.begin() + 1, dist.end());
  return ans == inf ? -1 : ans;
}


2 基于 Floyd 算法

在这里插入图片描述

说明:上图只是给出一个示例,并没有把整个更新过程画完整,请自行脑补。



2.1 代码说明

Step1:构建图(与 Dijkstra 算法一致)

Step2:更新距离

Floyd 算法的核心:不断尝试在点 i \mathrm{i} i 和点 j \mathrm{j} j 之间加入其他点 k \mathrm{k} k 作为中间点,如果加入 k \mathrm{k} k 之后的距离比加入 k \mathrm{k} k 之前的距离短,那么就更新点 i \mathrm{i} i 和点 j \mathrm{j} j 之间的距离。重复上述操作 n \mathrm{n} n 次,即可计算出任意两点之间的最短路径。

for (int k = 1; k <= n; ++k) {
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= n; ++j) {
      if (graph[i][k] >= 0 && graph[k][j] >= 0)
        graph[i][j] = graph[i][j] >= 0 ?
        min(graph[i][j], graph[i][k] + graph[k][j])
        : graph[i][k] + graph[k][j];
    }
  }
}

注意:中间点 k \mathrm{k} k 必须在最外层循环,否则一些路径无法被更新到;为什么判断条件是 > = 0 \mathrm{>= 0} >=0?因为题目给出的边的权值的范围为 [ 0 , 100 ] \mathrm{[0,100]} [0,100],所以需要包含 0 \mathrm{0} 0

Step3:返回结果

int ans = -1;
for (int j = 1; j <= n; ++j) {
  if (graph[k][j] == -1 && k != j)
    return -1;
  else if (k != j)
    ans = max(ans, graph[k][j]);
}
return ans;

由于我们只需要源点 k \mathrm{k} k 到其他点的距离,因此只需要遍历 g r a p h \mathrm{graph} graph 中的第 k \mathrm{k} k 行。

说明:由于我们在本方案中定义两点之间没有路径时的边的权值为 − 1 \mathrm{-1} 1,因此只要 g r a p h [ k ] [ j ] = = − 1 \mathrm{graph[k][j] == -1} graph[k][j]==1,就说明源点 k \mathrm{k} k 无法到达点 j \mathrm{j} j,因此返回 − 1 \mathrm{-1} 1



2.2 完整代码

int networkDelayTime(vector<vector<int>>& times, int n, int k) {
  vector<vector<int>> graph(n + 1, vector<int>(n + 1, -1));
  for (auto & t : times)
    graph[t[0]][t[1]] = t[2];

  for (int k = 1; k <= n; ++k) {
    for (int i = 1; i <= n; ++i) {
      for (int j = 1; j <= n; ++j) {
        if (graph[i][k] >= 0 && graph[k][j] >= 0)
          graph[i][j] = graph[i][j] >= 0 ?
          min(graph[i][j], graph[i][k] + graph[k][j])
          : graph[i][k] + graph[k][j];
      }
    }
  }

  int ans = -1;
  for (int j = 1; j <= n; ++j) {
    if (graph[k][j] == -1 && k != j)
      return -1;
    else if (k != j)
      ans = max(ans, graph[k][j]);
  }
  return ans;
}

虽然 Floyd 算法写起来没有 Dijkstra 算法繁琐,但是针对该问题的时间复杂度更高。



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

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

相关文章

灰色关联分析【系统分析+综合评价】

系统分析&#xff1a; 判断哪个因素影响最大 基本思想&#xff1a;根据序列曲线几何形状的相似程度来判断其练习是否紧密 绘制统计图并进行分析 确定子序列和母序列 对变量进行预处理&#xff08;去量纲、缩小变量范围&#xff09; 熟练使用excel与其公式和固定&#xff08…

微服务安全——OAuth2详解、授权码模式、SpringAuthorizationServer实战、SSO单点登录、Gateway整合OAuth2

文章目录 Spring Authorization Server介绍OAuth2.0协议介绍角色OAuth2.0协议的运行流程应用场景授权模式详解客户端模式密码模式授权码模式简化模式token刷新模式 OAuth 2.1 协议介绍授权码模式PKCE扩展设备授权码模式拓展授权模式 OpenID Connect 1.0协议Spring Authorizatio…

C语言数据结构:基于EasyX的飞机订票系统,有前端界面

数据结构课程设计说明书 学 院、系&#xff1a; 软件学院 专 业&#xff1a; 软件工程 班 级&#xff1a; 学 生 姓 名&#xff1a; 范 学 号&#xff1a; 设 计 题 目&#xff1a; 飞机订票系统 起 迄 日 期: 2024年6月18日~ 20…

笔记小结:现代卷积神经网络之批量归一化

本文为李沐老师《动手学深度学习》笔记小结&#xff0c;用于个人复习并记录学习历程&#xff0c;适用于初学者 训练深层神经网络是十分困难的&#xff0c;特别是在较短的时间内使他们收敛更加棘手。 本节将介绍批量规范化&#xff08;batch normalization&#xff09;&#xf…

vue3 + ts 报错:Parsing error: Unexpected token : eslint

报错&#xff1a;Parsing error: Unexpected token : eslint 解决&#xff1a; 在 .eslintrc.json 文件中加入 "parser": "babel/eslint-parser"配置 “parser”: “babel/eslint-parser” 告诉 ESLint 在检查代码之前&#xff0c;先使用 Babel 的解析器…

lua 游戏架构 之 游戏 AI (三)ai_attack

这段Lua脚本定义了一个名为 ai_attack 的类&#xff0c;继承自 ai_base 类。 lua 游戏架构 之 游戏 AI &#xff08;一&#xff09;ai_base-CSDN博客文章浏览阅读119次。定义了一套接口和属性&#xff0c;可以基于这个基础类派生出具有特定行为的AI组件。例如&#xff0c;可以…

深度学习:引领未来的人工智能技术(比喻)

深度学习&#xff1a;引领未来的人工智能技术 引言 随着人工智能&#xff08;AI&#xff09;的快速发展&#xff0c;深度学习&#xff08;Deep Learning&#xff09;作为其中最具革命性的技术之一&#xff0c;正在改变着各个行业。从自动驾驶到医疗诊断&#xff0c;从自然语言…

python—selenium爬虫

文章目录 Selenium与Requests对比一、工作原理二、功能特点三、性能表现 下载对应驱动1.首先我们需要打开edge浏览器&#xff0c;打开设置&#xff0c;找到“关于Microsoft Edge”&#xff0c;点击进入查看浏览器版本。2.查找版本之后&#xff0c;搜索edge驱动下载&#xff0c;…

Unity UGUI 之 ScrollBar与ScrollView

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 1.什么是ScrollBar 滚动块&#xff1a;Unity - Manual: Scrollbar 2.重要参数 该笔记来源…

MMROTATE的混淆矩阵confusion matrix生成

mmdetection中加入了混淆矩阵生成并可视化的功能&#xff0c;具体的代码在tools/analysis_tools/confusion_matrix.py。 mmrotate由于主流遥感数据集中的DOTA数据集标注格式问题&#xff0c;做了一些修改&#xff0c;所以我们如果是做遥感图像检测的Dota数据集的混淆矩阵&…

Elasticsearch介绍、安装以及IK分词器 --学习笔记

Elasticsearch 是什么&#xff1f; Elasticsearch 是一个高度可扩展的开源全文搜索和分析引擎。它允许你以极快的速度存储、搜索和分析大量数据。Elasticsearch 基于 Apache Lucene 构建&#xff0c;提供了一个分布式、多租户能力的全文搜索引擎&#xff0c;带有 HTTP web 接口…

centos系统mysql数据库压缩备份与恢复

文章目录 压缩备份一、安装 xtrabackup二、数据库中创建一些数据三、进行压缩备份四、模拟数据丢失&#xff0c;删库五、解压缩六、数据恢复 压缩备份 一、安装 xtrabackup 确保已经安装了 xtrabackup 工具。可以从 Percona 的官方网站 获取并安装适合你系统的版本。 # 添加…

2024在线PHP加密网站源码

源码介绍 2024在线PHP加密网站源码 更新内容: 1.加强算法强度 2.优化模版UI 加密后的代码示例截图 源码下载 https://download.csdn.net/download/huayula/89568335

学习日志:JVM垃圾回收

文章目录 前言一、堆空间的基本结构二、内存分配和回收原则对象优先在 Eden 区分配大对象直接进入老年代长期存活的对象将进入老年代主要进行 gc 的区域空间分配担保 三、死亡对象判断方法引用计数法可达性分析算法引用类型总结1&#xff0e;强引用&#xff08;StrongReference…

Python+Flask+MySQL+日线指数与情感指数预测的股票信息查询系统【附源码,运行简单】

PythonFlaskMySQL日线指数与情感指数预测的股票信息查询系统【附源码&#xff0c;运行简单】 总览 1、《股票信息查询系统》1.1 方案设计说明书设计目标工具列表 2、详细设计2.1 登录2.2 程序主页面2.3 个人中心界面2.4 基金详情界面2.5 其他功能贴图 总览 自己做的项目&#…

【教程】在 VS Code 集成终端中解决 Node.js 环境变量识别问题

背景 外部命令&#xff0c;如 node 在外部的终端中可以识别到&#xff0c;但是在vscode的终端中不能识别到错误&#xff1a;node : 无法将“node”项识别为 cmdlet、函数、脚本文件或可运行程序的名称也就是环境变量其实是有 node 的&#xff0c;但是 vscode 的集成终端中就是…

【Django】在vscode中新建Django应用并新增路由

文章目录 打开一个终端输入新建app命令在app下的views.py内写一个视图app路由引入该视图项目路由引入app路由项目(settings.py)引入app&#xff08;AntappConfig配置类&#xff09;运行项目 打开一个终端 输入新建app命令 python manage.py startapp antapp在app下的views.py内…

let、var、const 的区别 --js面试题

作用域 ES5中的作用域有&#xff1a;全局作用域、函数作用域&#xff0c;ES6中新增了块级作用域。块作用域由 { } 包括&#xff0c;if 语句和 for 语句里面的 { } 也属于块作用域。 var 1.没有块级作用域的概念&#xff0c;但具有函数全局作用域、函数作用域的概念 {var a …

交易积累-MACD

MACD&#xff08;Moving Average Convergence Divergence&#xff0c;即移动平均收敛发散指标&#xff09;是由Gerald Appel于1970年代后期发明的一种趋势跟踪动量指标。MACD显示了两个不同周期&#xff08;通常是较长和较短周期&#xff09;的移动平均线之间的差异。这个指标旨…

PCIe 以太网芯片 RTL8125B 的 spec 和 Linux driver 分析备忘

1,下载 RTL8125B driver 下载页&#xff1a; https://www.realtek.com/Download/List?cate_id584 2,RTL8125B datasheet下载 下载页&#xff1a; https://file.elecfans.com/web2/M00/44/D8/poYBAGKHVriAHnfWADAT6T6hjVk715.pdf3, 编译driver 解压&#xff1a; $ tar xj…