dijkstra算法相关(使用邻接表和优先队列两种方法)力扣题:743. 网络延迟时间(有向图);1334. 阈值距离内邻居最少的城市(无向图)

news/2024/11/8 20:35:45/

具体dijkstra算法就不展开说了,因为太多帖子来解释了,并且这也只是我的个人总结/记录,我会把自己的思考过程写在代码的注释中。

743. 网络延迟时间(有向图)

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

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

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

在这里插入图片描述

1. 邻接表法

	class Solution {
public:// distances数组 保存:起点k 到其他点的最短距离// visited数组 保存:某点是否被访问过了,被访问过则设置为true// graph 二维数组:邻接表// n : 节点总数void dijkstra(vector<vector<long long>>& graph,vector<int>& distances,int n,int k,vector<bool>& visited){distances[k] = 0;// 起始点到起始点自身的距离为0// 这里只需要循环 n-1次// 原因:除k点以外只有 n-1个点,每循环一次,就更新k点到一个点的距离for(int i = 1;i<=n-1;i++){int id = 0,minDistance = INT_MAX;for(int j = 1;j<=n;j++){// 这个循环的目的:去找 距离 k点最近的点// 原因:可以通过 这个点,去更新 其他点到 k点的距离if(!visited[j] && distances[j]<minDistance){minDistance = distances[j];id = j;}}// 所有点都被访问过了 或者 所有点都不可达if(id == 0) return;visited[id] = true;// 得到一个中间点 id后,比较k->id->某一点的距离 和 k->某一点的距离 // 来更新distances数组,注意,这个数组存的是k到某一点的距离for(int j = 1;j<=n;j++){if(!visited[j] && distances[id]+graph[id][j]<distances[j]){distances[j] = distances[id]+graph[id][j];}}}}int networkDelayTime(vector<vector<int>>& times, int n, int k) {vector<vector<long long>> graph(n+1,vector<long long>(n+1,INT_MAX));vector<int> distances(n+1,INT_MAX);vector<bool> visited(n+1,false);// 建立邻接表for(auto t:times){int u = t[0],v = t[1],w = t[2];graph[u][v] = w;}//dijkstra算法dijkstra(graph,distances,n,k,visited);int ans = 0;for(int i = 1;i<=n;i++){if(distances[i] == INT_MAX) return -1;ans = max(ans,distances[i]);}return ans;}
};

2. 优先队列

class Solution {
public:void dijktra(vector<vector<int>>& times,vector<int>& dis, int n, int k){dis[k] = 0;using Pair = pair<int,int>; // first是距离,second是目标点priority_queue<Pair,vector<Pair>, greater<Pair>> pq;pq.push({0,k});while(!pq.empty()){auto e = pq.top();pq.pop();if(e.first>dis[e.second]) continue;for(int i = 0;i<times.size();i++){if(times[i][0] == e.second){int v = times[i][1];// 到v点的的距离int w = e.first+times[i][2];if(dis[v]==-1 || dis[v]>w){dis[v] = w;pq.emplace(w,v);}}}}}int networkDelayTime(vector<vector<int>>& times, int n, int k) {vector<int> dis(n+1,-1);dijktra(times,dis,n,k);int ans = 0;for(int i = 1;i<=n;i++){if(dis[i]==-1) return -1;ans = max(ans,dis[i]);}return ans;}
};

1334. 阈值距离内邻居最少的城市

有 n 个城市,按从 0 到 n-1 编号。给你一个边数组 edges,其中 edges[i] = [fromi, toi, weighti] 代表 fromi 和 toi 两个城市之间的双向加权边,距离阈值是一个整数 distanceThreshold。

返回能通过某些路径到达其他城市数目最少、且路径距离 最大 为 distanceThreshold 的城市。如果有多个这样的城市,则返回编号最大的城市。

注意,连接城市 i 和 j 的路径的距离等于沿该路径的所有边的权重之和。

在这里插入图片描述

1. 邻接表法

class Solution {
public:void Dijkstra(vector<vector<long long>>& graph,vector<int>& distances,vector<bool> &visited,int n,int distanceThreshold,int start){// 自身到自身的距离为0distances[start] = 0;for(int i = 0;i<n-1;i++){int u = -1,minDis = INT_MAX;// 下面这个这个循环的目的:// 为了在 和 start 点相连的所有点中找到一个最近的点,再把它设为新的起点for(int j = 0;j<n;j++){if(!visited[j] && distances[j] <minDis){u = j; // 设置新的起点minDis =distances[j];}}// 如果所有点都访问过了 或者 不可达,直接return 即可if(u==-1) return;// 把新的起点设置为访问过visited[u] = true;// 接下来更新 start到所有点的 新的 距离// 为什么有新的距离?// 回答:因为此时我们有了一个新的点,那么从 start点开始到其他点就不止一种直连路线// 而是可以借助 刚刚确立好的新的点 ,比如从 start到某点 需要距离为5// 而start 到 u 的距离为1,u到某点的距离为2,那么就可以更新新的距离了for(int j = 0;j<n;j++){// 注意:仍然需要不去管那些已经访问过的节点//因为已经访问过的节点就已经是最短的距离了if(!visited[j] && distances[u]+graph[u][j]<distances[j]){distances[j] = distances[u]+graph[u][j];}}}}//  使用Dijkstra算法,邻接矩阵版int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {vector<vector<long long>> graph(n,vector<long long>(n,INT_MAX));// 邻接矩阵for(auto edge:edges){int u = edge[0],v = edge[1],w = edge[2];graph[u][v] = graph[v][u] = w;}// minCount:在指定的阈值内可以 到达节点 的最少数量int idx = -1,minCount = INT_MAX;for(int i = 0;i<n;i++){vector<int> distances(n,INT_MAX);// 单源最短路径数组vector<bool> visited(n,false); // 用来记录某一节点是否被访问过// 调用函数可以得到从i点出发到其他各个点的最短距离// 这些距离被保存在distances数组中Dijkstra(graph,distances,visited,n,distanceThreshold,i);int count = 0; // 小于等于阈值的城市个数for(int j = 0;j<n;j++){if(i!=j && distances[j] <= distanceThreshold  ){count++;}}if(count<=minCount){minCount = count;// 保存当下这个出发点idx = i;}}return idx;}
};

2. 优先队列

class Solution { //优先队列版
public:void Dijkstra(vector<vector<int>>& graph, vector<int>& distances, int n, int distanceThreshold, int start) {//小顶堆,按照距离dist从小到大排序,pair中first存distpriority_queue <pair<int, int>,vector<pair<int, int>>, greater<pair<int, int>>> q;distances[start] = 0;q.push({distances[start],start});while (!q.empty()) {pair<int, int>p = q.top();int u = p.second;q.pop();if (distances[u] < p.first) {continue;}for (int v=0; v<n; ++v) {if (graph[u][v] != INT_MAX && distances[v]>distances[u]+graph[u][v]) {distances[v]=distances[u]+graph[u][v];q.push({distances[v],v});}}}}int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {vector<vector<int>>graph(n,vector<int>(n,INT_MAX)); //邻接矩阵for (vector<int> edge : edges) {int u=edge[0], v=edge[1], w=edge[2];graph[u][v] = graph[v][u] = w;}int idx = -1, minCount = INT_MAX;for (int i=0; i<n; ++i) {vector<int>distances(n,INT_MAX); //单源最短路径数组Dijkstra(graph, distances, n, distanceThreshold, i);int count = 0; //小于等于距离阈值的城市个数for (int j=0; j<n; ++j) {if (distances[j]<=distanceThreshold && i!=j) {count++;}}if (count <= minCount) {minCount = count;idx = i;}}return idx;}
};

最后:

其实dijkstra算法(邻接表版本)对有向图和无向图使用起来都是一样的,没有区别。我之前会想如果我把[0,3,2]中的0和3调换会不会情况不一样,答案是不会的。因为在建邻接表的时候,就把双向的距离给设置好了,如果调换顺序,不过是从另一个点出发,距离仍然一样,并且也不用担心重复访问的问题,因为使用了visited数组来区分。


http://www.ppmy.cn/news/1007866.html

相关文章

java多线程并发面试题总结(史上最全40道)

1、多线程有什么用&#xff1f; 一个可能在很多人看来很扯淡的一个问题&#xff1a;我会用多线程就好了&#xff0c;还管它有什么用&#xff1f;在我看来&#xff0c;这个回答更扯淡。所谓"知其然知其所以然"&#xff0c;"会用"只是"知其然"&am…

数据结构--动态顺序表

文章目录 线性表动态顺序表数组与顺序表 接口实现初始化&#xff1a;尾插&#xff1a;尾删头插头删指定位置插入指定位置删除查找摧毁 完整代码 线性表 线性表是数据结构中最基本、最简单也是最常用的一种数据结构。线性表是指由n个具有相同数据类型的元素组成的有限序列。 线…

认识FFMPEG框架

FFMPEG全称: Fast Forward Moving Picture Experts Group (MPEG:动态图像专家组) ffmpeg相关网站: git://source.ffmpeg.org/ffmpeg.git http://git.videolan.org/?pffmpeg.git https://github.com/FFmpeg/FFmpeg FFMPEG框架基本组件: AVFormat , AVCodec, AVDevice, AVFil…

【测试学习五】测试类型的划分(重点:白盒与黑盒测试)

目录 一、测试类型的分类 1、按测试对象划分 2、是否查看代码划分&#xff08;重点&#xff09; &#x1f337;&#xff08;1&#xff09;黑盒测试 &#x1f337;&#xff08;2&#xff09;白盒测试 &#x1f337;&#xff08;3&#xff09;灰盒测试 3、按照开发阶段划…

关于cherry-pick的小实验

背景 好奇&#xff1a; 当前代码处于commit c1&#xff0c;分别拉出a、b两分支&#xff0c;切换到a分支&#xff0c;新增加一行信息&#xff0c;提交&#xff0c;得到c2&#xff0c;再在修改上一步所增加那行信息&#xff0c;得到c3。 此时a分支处于c3&#xff0c;b分支处于c…

【随笔记】Linux/Win 平台调用外部命令并获取执行结果

Linux&#xff1a; 有些命令输出结果并不是通过 ”标准输出“&#xff0c;而是通过 "错误输出"&#xff0c;因此为了能获取到所有的执行结果&#xff0c;需要将 "错误输出" 重定向 "标准输出"。 bool runShellCommand(std::string &result…

Linux下C/C++的gdb工具与Python的pdb工具常见用法之对比

1、gdb和pdb分别是什么&#xff1f; 1.1、gdb GDB&#xff08;GNU Debugger&#xff09;是一个功能强大的命令行调试工具&#xff0c;由GNU项目开发&#xff0c;用于调试C、C等编程语言的程序。它在多个操作系统中都可以使用&#xff0c;包括Linux、MacOS和Windows&#xff0…

Python 扩展 快捷贴士:os模块下的创建目录的方式

Python3 os.makedirs() 方法 概述 os.makedirs() 方法用于递归创建多层目录。 如果子目录创建失败或者已经存在&#xff0c;会抛出一个 OSError 的异常&#xff0c;Windows上Error 183 即为目录已经存在的异常错误。 如果第一个参数 path 只有一级&#xff0c;即只创建一层目…