算法题 - 图论 - Dijkstra

算法题 - 图论 - Dijkstra

  • 1. 理论
    • 1.1 稠密图和稀疏图
      • 根据边数量和节点数量分辨
      • 根据存储方式和空间复杂度分辨
      • 根据算法效率和时间复杂度分辨
    • 1.2 邻接矩阵和邻接表
      • 邻接矩阵
        • 存储方式
        • 特点
        • 示例代码
      • 邻接表
        • 存储方式
        • 特点
        • 示例代码
    • 1.3 易错点
      • 重边
      • 数据量
      • 无向图的建图
  • 743. 网络延迟时间(medium)
  • 3112. 访问消失节点的最少时间(medium)
  • 3341. 到达最后一个房间的少时间 I(medium)
  • 3342. 到达最后一个房间的少时间 II(medium)
  • 2642. 设计可以求最短路径的图类(hard)
  • 1514. 概率最大的路径(medium)
  • 1631. 最小体力消耗路径(medium)
  • 1786. 从第一个节点出发到最后一个节点的受限路径数(medium)

1. 理论

1.1 稠密图和稀疏图

在图论中,稠密图和稀疏图是对图中边的分布情况的一种描述

根据边数量和节点数量分辨

对于一个具有 n 个顶点的图

  • 如果是有向图,其边数最多为 n(n - 1)
  • 如果是无向图,其边数最多为 n(n - 1) / 2

那么可以大致根据边数可以粗略分辨一个图是稠密还是稀疏

  • 如果是有向图,其边数无限接近 n(n - 1),则为稠密图,反之稀疏
  • 如果是无向图,其边数无限接近 n(n - 1) / 2,则为稠密图,反之稀疏

根据存储方式和空间复杂度分辨

  • 如果使用邻接矩阵来存储图时所占用的空间与使用邻接表存储时相差不大,甚至邻接矩阵更优,那么该图大概率是稠密图。因为邻接矩阵的空间复杂度为O(n ^ 2) ,而邻接表的空间复杂度为O(n + 边数),如果边数无限接近 n,那么邻接表的空间复杂度也是O(n ^ 2)

根据算法效率和时间复杂度分辨

一般来说,如果一幅图中不同的边的数 量在顶点总数 n 的一个小的常数倍以内(< n^2),那么我们就认为这幅图是稀疏的,否则则是稠密的。
在 单源最短路 - Dijkstra 算法中,根据节点数量 n 和边的实际数量 m 决定这个图是稠密还是稀疏

  • 比较 n^2 和 m * logm 的大小
  • 如果 n ^ 2 比较小,说明是稠密图
  • 如果 m * logm 比较小,说明是稀疏图

1.2 邻接矩阵和邻接表

  • 邻接矩阵和邻接表是图论中两种常用的"表示图"的数据结构

邻接矩阵

存储方式
  • 用一个二维数组 arr 存储图(大小为 n * n,n为图的节点数量)
  • 如果 x 至 y 存在一条边,arr[x][y] 对应的点意思是从 x 节点 到 y 节点的权值
  • 如果 x 至 y 不存在边,可以放 0 或者 其他值。
特点
  • 直观性:能够直观地表示图中顶点之间的连接关系,通过矩阵的行列对应顶点,元素值表示边的存在与否或边的权值,易于理解和实现。
  • 易于判断顶点间的连接性:要判断顶点和是否有边相连,只需查看矩阵中的值即可,时间复杂度为 O(1)。
  • 适合稠密图:对于边数相对较多的稠密图,邻接矩阵能够高效地存储和处理图的信息,不会浪费过多的存储空间。
示例代码
vector<vector<int>> g(n,vector<int>(n));  //二维数组
.... // 根据题给出的边输入到对应的坐标中

邻接表

存储方式
  • 邻接表是一种链式存储结构,用于表示图中每个顶点的邻接顶点集合
  1. 首先需要一个长度为 n 的一维数组
  2. 其次数组每个元素底下挂的不同长度的集合(集合每个元素存放的是(连接的节点 和 边的权值))
特点
  • 高效存储稀疏图:对于边数较少的稀疏图,邻接表只存储实际存在的边,相比邻接矩阵能够节省大量的存储空间,空间复杂度为(n + m),其中 n 是顶点数,m 是边数。
  • 方便遍历顶点的邻接点:通过遍历顶点对应的链表,可以快速获取该顶点的所有邻接顶点
示例代码
 typedef pair<int,int> pii; //利用pair存放 y 和 权值vector<vector<pii>> g(n + 1);  // 数组成员类型也可以是 list<pii>

1.3 易错点

重边

  • 如果题目给的数据中,两个节点可能有多个边,邻接矩阵根据题意取最大值或者最小值,邻接表无需改变。

数据量

  • 实际上大部分的题都是稀疏图,节点数量也可会很大,往往使用邻接矩阵会超出内存限制,因此首选用节省空间的邻接表构图比较稳妥,但不一定时间复杂度占优。

无向图的建图

  • 在无向图中建图时需要注意,如果 x -> y 如果存在边
  • 无论是邻接矩阵还是邻接表,都需要添加 x->y 和 y->x 的权值

743. 网络延迟时间(medium)

https://leetcode.cn/problems/network-delay-time/description/

  • 邻接矩阵写法
class Solution {
public:int networkDelayTime(vector<vector<int>>& times, int n, int k) {int m = INT_MAX/2;//本题节点不多,可以构造邻接矩阵,g[i][j] 表示从i到j的边权值,如果到不了则为一个较大值vector<vector<int>> g(n + 1,vector<int>(n + 1,m)); for(auto& t : times) g[t[0]][t[1]] = t[2];//存从起点开始到当前点位的最短路径vector<int> dis(n + 1,m);  //起点路径长度设0dis[k] = 0; //每找到一个节点的最短路径,设为truevector<bool> fis(n +1); //记录找到最短路径节点的数量int count = 0; while(true){//1. 通过遍历找起点int x = -1;for(int i = 1;i<=n;i++){if(!fis[i] && (x == -1 || dis[i] < dis[x]))x = i;}//2. 判断起点是否合法if(dis[x] == m) return -1;//3. 如果能作为起点,说明此点已经有最短路径fis[x] = true;count++;//4. 如果count表示计数完毕,说明这个点已经是最后一个点,返回即可if(count == n) return dis[x];//5. 上面如果都没返回,这里更新每个点位的最短路径for(int i= 1;i<=n;i++){dis[i] = min(dis[i],dis[x] + g[x][i]);}}return -1;}
};
  • 邻接表写法
class Solution {
public:typedef pair<int,int> pii;int networkDelayTime(vector<vector<int>>& times, int n, int k) {vector<vector<pii>> g(n + 1);for(auto& t:times)  g[t[0]].emplace_back(t[1],t[2]);priority_queue<pii,vector<pii>,greater<>> qe;qe.emplace(0,k);vector<int> dis(n + 1, -1);dis[k] = 0;int count = 0;while(qe.size()){auto [v,x] = qe.top();qe.pop();if(v > dis[x]) continue;if(++count == n) return v;for(auto &[y, len] : g[x]){int newdis = v + len;if(dis[y] == -1 || dis[y] > newdis){qe.emplace(newdis,y);dis[y] = newdis;}}}return -1;} 
};

3112. 访问消失节点的最少时间(medium)

https://leetcode.cn/problems/minimum-time-to-visit-disappearing-nodes/

class Solution {
public:typedef pair<int,int> pii;vector<int> minimumTime(int n, vector<vector<int>>& edges, vector<int>& disappear) {vector<vector<pii>> g(n); //本题节点较多,适合构造邻接表for(auto &e : edges){//对于无向边,节点互相连通g[e[0]].emplace_back(e[1],e[2]);g[e[1]].emplace_back(e[0],e[2]);} //优化- 小根堆寻找起点priority_queue<pii,vector<pii>,greater<>> qe; qe.emplace(0,0);//记录 0 到所有节点的最短路径vector<int> dis(n, - 1); dis[0] = 0;while(qe.size()){//1. 寻找起点auto [l,x] = qe.top();qe.pop();//2. 这个点已经有存在更短路径,跳过下面步骤if(dis[x] < l)  continue;//3. 遍历以x做起点,到达其他节点的时间for(auto &[a,b] : g[x]){//计算从 0 到达这个点的总时长int newdis = dis[x] + b;//必须保证这个点不是最优状态,并且没消失if(newdis < disappear[a]){if(dis[a] == -1 || dis[a] > newdis){qe.emplace(newdis,a);dis[a] = newdis;}}} }return dis;}
};

3341. 到达最后一个房间的少时间 I(medium)

https://leetcode.cn/problems/find-minimum-time-to-reach-last-room-i/

class Solution {
public:int dx[4] = {0,0,1,-1};int dy[4] = {1,-1,0,0};typedef tuple<int,int,int> tp;int minTimeToReach(vector<vector<int>>& moveTime) {int n = moveTime.size();int m = moveTime[0].size();//记录从(0,0)到所有点位的耗时vector<vector<int>> dis(n,vector<int>(m, -1));dis[0][0] = 0;//优化每次寻找起点的时间priority_queue<tp,vector<tp>,greater<>> qe;qe.emplace(0,0,0);while(qe.size()){//1. 找起点auto [t,x,y] = qe.top(); qe.pop();//2. if(dis[x][y] < t) continue; if(x == n - 1 && y == m - 1) return t;for(int i = 0;i<4;i++){int x1 = dx[i] + x;int y1 = dy[i] + y;if(x1>=0 && x1<n && y1>=0 && y1< m){int newtime = max(moveTime[x1][y1], dis[x][y]) + 1;if(dis[x1][y1] == -1 || dis[x1][y1] > newtime){dis[x1][y1] = newtime;qe.emplace(newtime,x1,y1);}}}}   return dis[n - 1][m - 1];}
};

3342. 到达最后一个房间的少时间 II(medium)

https://leetcode.cn/problems/find-minimum-time-to-reach-last-room-ii/

class Solution {
public:int dx[4] = {0,0,1,-1};int dy[4] = {1,-1,0,0};typedef tuple<int,int,int> tp;int minTimeToReach(vector<vector<int>>& moveTime) {int n = moveTime.size();int m = moveTime[0].size();vector<vector<int>> dis(n,vector<int>(m, -1)); dis[0][0] = 0;priority_queue<tp,vector<tp>,greater<>> qe; qe.emplace(0,0,0);while(qe.size()){auto [t,x,y] = qe.top(); qe.pop();if(dis[x][y] < t) continue;if(x == n - 1 && y == m - 1) return t;for(int i = 0;i<4;i++){int x1 = dx[i] + x;int y1 = dy[i] + y;if(x1>=0 && x1<n && y1>=0 && y1< m){//除开第0个房间,其他房间横竖坐标相加为奇数则额外耗时1,否则额外耗时2int newtime = max(moveTime[x1][y1], dis[x][y]) + (x1 + y1 + 1)%2 + 1;if(dis[x1][y1] == -1 || dis[x1][y1] > newtime){dis[x1][y1] = newtime;qe.emplace(newtime,x1,y1);}}}}   return dis[n - 1][m - 1];}
};

2642. 设计可以求最短路径的图类(hard)

https://leetcode.cn/problems/design-graph-with-shortest-path-calculator/

class Graph {typedef pair<int,int> pii;
public:Graph(int n, vector<vector<int>>& edges):_n(n){g.resize(_n);for(auto& e: edges) g[e[0]].emplace_back(e[1],e[2]);}void addEdge(vector<int> edge) {g[edge[0]].emplace_back(edge[1], edge[2]);}int shortestPath(int node1, int node2) {priority_queue<pii,vector<pii>,greater<>> qe;qe.emplace(0,node1);vector<int> dis(_n,-1);dis[node1] = 0;while(qe.size()){auto [v,x] = qe.top(); qe.pop();if(v > dis[x]) continue;if(x == node2) return v;for(auto&[y,len] : g[x]){   int newdis = v + len;if(dis[y] == -1 || dis[y] > newdis){dis[y] = newdis;qe.emplace(newdis,y);}}}  return -1;}
private:vector<vector<pii>> g; //邻接矩阵int _n = 0; //节点数量
};

1514. 概率最大的路径(medium)

https://leetcode.cn/problems/path-with-maximum-probability/

class Solution {
public:typedef pair<double,int> pdi;double maxProbability(int n, vector<vector<int>>& edges, vector<double>& succProb, int start_node, int end_node) {vector<vector<pdi>> g(n);for(int i = 0;i<edges.size();i++) {g[edges[i][0]].emplace_back(succProb[i],edges[i][1]);g[edges[i][1]].emplace_back(succProb[i],edges[i][0]);}priority_queue<pdi> qe;qe.emplace(1,start_node);vector<double> dis(n, -1);dis[start_node] = 1;while(qe.size()){auto [v, x] = qe.top(); qe.pop();if(v < dis[x]) continue;if(x == end_node) return v;for(auto& [len, y] : g[x]){double newdis = v * len;if(dis[y] == -1 || dis[y] < newdis){dis[y] = newdis;qe.emplace(newdis,y);}}}return 0;}
};

1631. 最小体力消耗路径(medium)

https://leetcode.cn/problems/path-with-minimum-effort/

class Solution {
public:typedef tuple<int,int,int> tp;int dx[4] = {1,-1,0,0};int dy[4] = {0,0,1,-1};int minimumEffortPath(vector<vector<int>>& heights) {priority_queue<tp,vector<tp>,greater<>> qe;qe.emplace(0,0,0);int row = heights.size();int col = heights[0].size();vector<vector<int>> dis(row,vector<int>(col,-1));dis[0][0] = 0;while(qe.size()){auto [v, x, y] = qe.top();qe.pop();if(v > dis[x][y]) continue;if(x == row - 1 && y == col - 1) return v;for(int i = 0;i<4;i++){int x1 = dx[i] + x;int y1 = dy[i] + y;if(x1 >=0 && x1 < row && y1>=0 && y1 < col){int newdis = abs(heights[x1][y1] - heights[x][y]);newdis = max(newdis, v);if(dis[x1][y1] == -1 || dis[x1][y1] > newdis){dis[x1][y1] = newdis;qe.emplace(newdis,x1,y1);}}}}return -1;}
};

1786. 从第一个节点出发到最后一个节点的受限路径数(medium)

https://leetcode.cn/problems/number-of-restricted-paths-from-first-to-last-node/

class Solution {
public:typedef pair<int, int> pii;int N = 1e9 + 7;int countRestrictedPaths(int n, vector<vector<int>>& edges) {//找列出最小路径vector<vector<pii>> g(n + 1);for (auto& e : edges) {g[e[0]].emplace_back(e[1], e[2]);g[e[1]].emplace_back(e[0], e[2]);}priority_queue<pii, vector<pii>, greater<>> qe;qe.emplace(0, n);vector<int> dis(n + 1, -1);dis[n] = 0;while (qe.size()) {auto [v, x] = qe.top();qe.pop();if (dis[x] < v)continue;for (auto& [y, l] : g[x]) {int newdis = v + l;if (dis[y] == -1 || dis[y] > newdis) {dis[y] = newdis;qe.emplace(newdis, y);}}}// dpvector<int> index(n + 1);for (int i = 1; i <= n; i++)index[i] = i;sort(index.begin() + 1, index.end(),[&](int i, int j) { return dis[i] < dis[j]; });vector<int> dp(n + 1, 0);dp[n] = 1;for (int i = 2;;i++) {int a = index[i];for (auto& [node, l] : g[a])if (dis[a] > dis[node]) {dp[a] += dp[node];dp[a] %= N;}if (a == 1)break;}return dp[1] % N;}
};

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

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

相关文章

Vanna使用ollama分析本地MySQL数据库 加入redis保存训练记录

相关代码 from vanna.base.base import VannaBase from vanna.chromadb import ChromaDB_VectorStore from vanna.ollama import Ollama import logging import os import requests import json import pandas as pd import chromadb import redis import pickle from IPython.…

基于Java Springboot校园疫情防控系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…

《探索 Spring 核心容器:Bean 的奇妙世界》

一、Spring 核心容器与 Bean 的关系 Spring 核心容器是 Spring 框架的重要组成部分&#xff0c;负责管理和组织应用程序中的对象&#xff0c;而 Bean 则是构成应用程序主干并由 Spring IoC 容器管理的对象&#xff0c;二者紧密相连。 Spring 的核心容器由多个模块组成&#xf…

基于卷积神经网络的航空发动机剩余寿命预测Matlab实现

本文利用NASA提供的涡扇发动机退化数据集&#xff0c;进行数据预处理&#xff0c;构建训练样本和测试样本&#xff0c;然后搭建卷积神经网络&#xff08;Convolutional Neural Network,CNN&#xff09;&#xff0c;学习训练数据&#xff0c;最后利用测试数据&#xff0c;分析神…

day02(单片机高级)单片机控制ESP8266连接阿里云

目录 单片机控制ESP8266连接阿里云物联平台 MQTT协议简介 订阅和发布 cJSON简介 云平台搭建 注册和登录 实例的开通和创建 产品和设备的创建 创建产品 添加设备 功能定义 发布上线 MQTTFX工具使用 发布和订阅 订阅 发布 MQTT固件烧录 AT指令验证 调试验证订阅 单片机控制ESP826…

社交电商的优势及其与 AI 智能名片小程序、S2B2C 商城系统的融合发展

摘要&#xff1a;本文深入分析了社交电商相较于传统电商的优势&#xff0c;包括门槛低、易操作、更生活化和可团队化运作等特点。同时&#xff0c;探讨了 AI 智能名片小程序和 S2B2C 商城系统在社交电商发展中的作用&#xff0c;以及它们与社交电商融合所带来的新机遇和发展前景…

uni-app快速入门(八)--常用内置组件(上)

uni-app提供了一套基础组件&#xff0c;类似HTML里的标签元素&#xff0c;不推荐在uni-app中使用使用div等HTML标签。在uni-app中&#xff0c;对应<div>的标签是view&#xff0c;对应<span>的是text&#xff0c;对应<a>的是navigator&#xff0c;常用uni-app…

Jmeter的后置处理器(二)

5--JSR223 PostProcessor 功能特点 自定义后处理逻辑&#xff1a;使用脚本语言编写自定义的后处理逻辑。支持多种脚本语言&#xff1a;支持 Groovy、JavaScript、BeanShell 等脚本语言。动态参数传递&#xff1a;将提取的数据存储为变量&#xff0c;供后续请求使用。灵活性高…

基于SpringBoot3+mybatis搭建的历史上的今天API接口服务 及 Mybatis 应该有个更好的方法来隐藏 Pojo 类中的字段

一、Mybatis有没有比较好的方法隐藏 Pojo 类中的字段 使用 Mybatis 时&#xff0c;为了实现通用的CURD&#xff0c;在定义实体类pojo时&#xff0c;会尽量将能用得上的数据库字段都定义到 pojo中&#xff0c;但是在查询的时候却有不一样的需求。mybatis的文档地址链接&#xff…

SLAM-evo 评估

文章目录 1.evo介绍1.1.evo安装1.1.2.evo的安装(evo共有两种安装方式)1.1.2.1.采用pip安装&#xff0c;直接安装最新的稳定发行版&#xff08;在翻墙的情况下可以使用&#xff09;将路径添加到系统 PATH 中1.1.2.2.源码安装 &#xff0c;下载源码进行安装&#xff08;必须翻墙&…

【机器学习chp3】判别式分类器:线性判别函数、线性分类器、广义线性分类器、分段线性分类器

前言&#xff1a; 本文遗留问题&#xff1a;&#xff08;1&#xff09;对最小平方误差分类器的理解不清晰.&#xff08;2&#xff09;分段线性判别函数的局部训练法理解不清晰。 推荐文章1&#xff0c;其中有关于感知机的分析 【王木头从感知机到神经网络】-CSDN博客 推荐文…

04 搭建linux驱动开发环境

虽然 petalinux 功能很全面&#xff0c;但是其编译速度较慢&#xff0c;不适用于驱动调试阶段&#xff08;因为驱动调试阶段会频繁修改驱动模块、内核、设备树等&#xff09;&#xff0c;因此本章将采用分步编译的方式来编译启动开发板所需要的各种镜像文件&#xff0c;虽然步骤…

Linux性能优化之火焰图的起源

Linux火焰图的起源与性能优化专家 Brendan Gregg 密切相关&#xff0c;他在 2011 年首次提出这一工具&#xff0c;用于解决性能分析过程中可视化和数据解读的难题。 1. 背景&#xff1a;性能优化的需求 在现代计算中&#xff0c;性能优化往往需要对程序执行中的热点和瓶颈进行…

半桥驱动芯片调试中的问题

结论&#xff1a;低于12V的场景应用分立的MOS驱动电路压根不合适&#xff0c;选用集成桥臂的芯片合适。 HIN的输入电平不能是长时间的高电平&#xff0c;否则自举电容没法充放电从而没办法自举升压&#xff0c;上管无法控制&#xff1a; 电容C2的容值应该尽可能大&#xff…

【C++】类和对象-深度剖析默认成员函数-上

> &#x1f343; 本系列为初阶C的内容&#xff0c;如果感兴趣&#xff0c;欢迎订阅&#x1f6a9; > &#x1f38a;个人主页:[小编的个人主页])小编的个人主页 > &#x1f380; &#x1f389;欢迎大家点赞&#x1f44d;收藏⭐文章 > ✌️ &#x1f91e; &#x1…

RabbitMQ黑马笔记

目录 1.初识MQ 1.1.同步和异步通讯 1.1.1.同步通讯 1.1.2.异步通讯 1.2.技术对比&#xff1a; 2.快速入门 2.1.安装RabbitMQ 2.2.RabbitMQ消息模型 2.3.导入Demo工程 2.4.入门案例 2.4.1.publisher实现 2.4.2.consumer实现 2.5.总结 3.SpringAMQP 3.1.Basic Queu…

麒麟KylinServer的网站,并部署一套主从DNS服务器提供域名解析服务

一、KylinServer网站搭建 ifconfig Copy 注意:根据实际网卡设备名称情况调整代码!不同环境下网卡名称略有不同! 获取本机IP地址,记住IP地址用于之后的配置填写。 ifconfig enp0s2 Copy 下载nginx源码包,并解压缩 wget http://10.44.16.102:60000/allfiles/Kylin/ng…

解决IntelliJ IDEA的Plugins无法访问Marketplace去下载插件

勾选Auto-detect proxy setting并填入 https://plugins.jetbrains.com 代理URL&#xff0c;可以先做检查连接&#xff1a;

AWTK-WIDGET-WEB-VIEW 发布

awtk-widget-web-view 是通过 webview 提供的接口&#xff0c;实现的 AWTK 自定义控件&#xff0c;使得 AWTK 可以方便的显示 web 页面。 项目网址&#xff1a; https://gitee.com/zlgopen/awtk-widget-web-view webview 提供了一个跨平台的 webview 接口&#xff0c;是一个非…

Pandas教程之Pandas 简介

Pandas 简介 接下来一段时间&#xff0c;我会持续发布并完成Pandas教程 Pandas 是一个功能强大的开源 Python 库。Pandas 库用于数据操作和分析。Pandas 由数据结构和函数组成&#xff0c;可对数据执行有效的操作。 本免费教程将概述 Pandas&#xff0c;涵盖 Python Pandas 的基…