邻接矩阵和邻接表_[力扣743] 带权邻接表的单源最短路

896e39d1908647e561ff98087d92044c.png

题目链接

743. 网络延迟时间

题目描述

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

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

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

样例

输入:times = [[2,1,1],[2,3,1],[3,4,1]], N = 4, K = 2输出:2

数据范围

N 的范围在 [1, 100] 之间。
K 的范围在 [1, N] 之间。
times 的长度在 [1, 6000] 之间。
所有的边 times[i] = (u, v, w) 都有 1 <= u, v <= N 且 0 <= w <= 100。

算法

图论的题目一般是 3 步,建图 -> 图论算法 -> 后处理。

本题也是一样的思路:先建邻接表,然后求单源最短路,然后根据找到的各个点的最短路,找到从起始点出发可以到达的最远的距离。

一般比较难的题目难点都是在建图这一步。有的是非常隐晦的图论问题,想不到建图处理,例如 127. 单词接龙;有的是建图过程中 corner case 非常多,很容易漏,例如 444. 序列重建。成功完成建图之后(一般是建邻接表比较多),之后的图论算法就比较模板化了。

当边的权都相同时,求最短路直接一趟 BFS就可以,典型题目 1091. 二进制矩阵中的最短路径。当边权不同的时候有以下几种。

dijkstra 数组实现: O(E + V^2),有贪心思想,不能处理负权
dijkstra 堆实现: O(ElogV + VlogV),有贪心思想,不能处理负权
bellman ford: O(VE), 可以处理负权,可以检测负环
spfa: O(VE), bellman ford 的优化, 可以处理负权,可以检测负环
floyd: O(V^3) 可以把所有点之间的最短路径求出,如果求多源最短路,时间复杂度可摊销

如果没有负权的话,一般使用 dijkstra 最好。

代码(c++)

代码框架就是 建立邻接表 -> 单源最短路算法 -> 后处理

单源最短路算法的 5 种算法都是模板,对应的实现在引申部分

class Solution {
public:int networkDelayTime(vector<vector<int>>& times, int N, int K) {vector<vector<vector<int> > > g(N + 1);for(vector<int> &edge: times)g[edge[0]].push_back({edge[1], edge[2]});// 求带权邻接表的最短路vector<int> d = dijkstra_array(g, K, N);// vector<int> d = dijkstra_heap(g, K, N);// vector<int> d = bellman_ford(g, K, N);// vector<int> d = spfa(g, K, N);// vector<int> d = floyd(g, K, N);int res = 0;for(int i = 1; i <= N; i++){if(d[i] == -1)return -1;res = max(res, d[i]);}return res;}
};

引申: 权邻接表的单源最短路模板代码

接口:

// g 是建好的邻接表,start 是起始点,N 是节点个数; 返回各个点到 start 的最短路径
vector<int> shortest_path(vector<vector<vector<int> > >& g, int start, int N);

5个算法的接口都一样,下面是对应的模板代码,原理部分没有展开。

如果能够将问题转化成模板问题,再套模板就轻松愉快了。这个有点类似下棋或者炒菜的背谱,只会背谱肯定是不好的,但是背谱可以快速下出挑不出什么毛病的棋,快速炒出80分的菜。

1. dijkstra 数组实现

vector<int> dijkstra_array(vector<vector<vector<int> > >& g, int start, int N)
{// dijkstra 数组实现 O(E + V^2)// 不能有负权// 存放 start 到各个点的最短路径vector<int> d(N + 1, -1);d[start] = 0;// 记录是否找到 start 到该点的最短路径vector<bool> visited(N + 1, false);visited[start] = true;// 初始化 start 到各个点的距离for(vector<int> son: g[start])d[son[0]] = son[1];for(int cnt = 1; cnt <= N - 1; ++cnt){int min_val = INT_MAX / 2, min_idx = 0;// 遍历所有节点,找到离 start 最近的节点for(int i = 1; i <= N; ++i){if(d[i] != -1 && !visited[i] && d[i] < min_val){min_idx = i;min_val = d[i];}}// 标记离 start 最近距离节点已经找到visited[min_idx] = true;// 根据刚刚找到的距离 start 最短的节点,// 通过该节点更新 start 与其它节点的距离for(vector<int> son: g[min_idx]){if(d[son[0]] != -1) // 之前路径与当前更新路径的最小值d[son[0]] = min(d[son[0]], min_val + son[1]);else // 该节点第一次访问,直接更新d[son[0]] = min_val + son[1];}}return d;
}

2. dijkstra 堆实现

vector<int> dijkstra_heap(vector<vector<vector<int> > >& g, int start, int N)
{// dijkstra 堆实现 O(ElogV + VlogV)// 不能有负权// 存放 start 到各个点的最短路径vector<int> d(N + 1, INT_MAX / 2);d[start] = 0;priority_queue<vector<int>, vector<vector<int> >, Cmp> pq; // 队列元素 (节点编号,到 start 的距离)pq.push({start, 0});while(!pq.empty()){vector<int> cur = pq.top();pq.pop();if(d[cur[0]] < cur[1]) continue;for(vector<int> son: g[cur[0]]){if(d[son[0]] <= d[cur[0]] + son[1]) continue;d[son[0]] = d[cur[0]] + son[1];pq.push({son[0], d[son[0]]});}}return d;
}struct Cmp
{bool operator() (const vector<int>& item1, const vector<int>& item2){return item1[1] > item2[1]; // 最小堆}
};

3. bellman ford

松弛操作,它的原理是著名的定理:“三角形两边之和大于第三边”

vector<int> bellman_ford(vector<vector<vector<int> > >& g, int start, int N)
{// bellman ford  O(VE)// 可以检测负环vector<int> d(N + 1, -1);d[start] = 0;// 进行 N - 1 轮松弛// 因为任意两点之间最短路最多包含 N - 1 条边for(int cnt = 1; cnt <= N - 1; ++cnt){// u: 源节点,v: 子节点, w: uv 的权for(int u = 1; u <= N; ++u){if(d[u] == -1) continue;for(vector<int> &son: g[u]){int v = son[0], w = son[1];// 判断能否通过 u -> v 缩短 d[v] (松弛)if(d[u] + w < d[v] || d[v] == -1)d[v] = d[u] + w;}}}/* 可以检测负环for(int u = 1; u <= N; ++u){for(vector<int> &son: g[u]){int v = son[0], w = son[1];if(d[u] + w < d[v])// 有负环}}*/return d;
}

4. spfa

SPFA算法的基本思想:在Bellman-Ford算法中,很多松弛操作其实都是没有必要的,例如对于一条从 x 到 y 的边,如果连 x 都还没被松弛,那 y 肯定也还不能被 x 松弛。用一个队列来存储已经被松弛过的点,然后用队列里的点去松弛其他点,就可以避免用一个还没有被松弛的点去松弛另外的点。

vector<int> spfa(vector<vector<vector<int> > >& g, int start, int N)
{// 与 bellman ford 相同, O(VE)// 可以检测负环vector<int> d(N + 1, -1);d[start] = 0;queue<int, list<int> > q;q.push(start);// 记录每个点到 start 的节点个数vector<int> cnt(N + 1, 0);cnt[start] = 1;while(!q.empty()){int cur = q.front();q.pop();for(vector<int> &son: g[cur]){if(d[son[0]] == -1 || d[son[0]] > d[cur] + son[1]){cnt[son[0]] = cnt[cur] + 1;if(cnt[son[0]] > N) return d; // 若 son 到 start 的节点个数大于 N 了说明有负环// 当最短距离发生变化且不在队列中时,将该节点加入队列d[son[0]] = d[cur] + son[1];q.push(son[0]);}}}return d;
}

5. floyd

vector<int> floyd(vector<vector<vector<int> > >& g, int start, int N)
{// floyd 需要邻接矩阵 O(V^3)// 可以做多源最短路vector<vector<int> > adj_matrix(N + 1, vector<int>(N + 1, -1));for(int i = 1; i <= N; ++i)adj_matrix[i][i] = 0;for(int u = 1; u <= N; ++u)for(vector<int> son: g[u])adj_matrix[u][son[0]] = son[1];// 遍历所有节点,其中 k 是用于松弛的点for(int k = 1; k <= N; ++k)for(int i = 1; i <= N; ++i)for(int j = 1; j <= N; ++j)// 使用 k 松弛 i -> j 的最短路径if(adj_matrix[i][k] != -1 && adj_matrix[k][j] != -1){if(adj_matrix[i][j] != -1)adj_matrix[i][j] = min(adj_matrix[i][j], adj_matrix[i][k] + adj_matrix[k][j]);elseadj_matrix[i][j] = adj_matrix[i][k] + adj_matrix[k][j];}vector<int> d(N + 1, -1);for(int i = 1; i <= N; ++i)d[i] = adj_matrix[start][i];return d;
}

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

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

相关文章

opencv java ubuntu_Ubuntu 16.04配置OpenCV 3.1.0 for Java

我们都知道&#xff0c;OpenCV是基于C的开源计算机视觉库&#xff0c;但是从2.4.4版本开始提供了Java绑定&#xff0c;也就是说&#xff0c;我们也可以使用Java来开发基于OpenCV的计算机视觉应用。目前&#xff0c;最新的版本是3.1.0&#xff0c;在本文中将会介绍如何中Ubuntu …

service 层 拼接的html 代码如何直接返回_字符串拼接,会走StringBuilder 吗?

前言最近在突然想到了String字符串拼接问题&#xff0c;于是做了一个demo测试了一下&#xff0c;到底String类型的字符串在拼接的时候&#xff0c;哪种情况下会走会走StringBulider进行字符串拼接&#xff0c;而哪种情况编译器会对代码进行优化&#xff1f;话不多说&#xff0c…

迁移学习训练集准确率一直上不去_可以提高你的图像识别模型准确率的7个技巧...

假定&#xff0c;你已经收集了一个数据集&#xff0c;建立了一个神经网络&#xff0c;并训练了您的模型。但是&#xff0c;尽管你投入了数小时(有时是数天)的工作来创建这个模型&#xff0c;它还是能得到50-70%的准确率。这肯定不是你所期望的。下面是一些提高模型性能指标的策…

华为云客户端_华为公布云手机计费清单,要不要光刻机也给出了答案

华为云手机一出来&#xff0c;大家的好奇心就上来了。这就是解决华为无芯片的代替方案。纷纷说道&#xff0c;可以绕开光刻机&#xff0c;光刻机瞬间变废铁。当时我还发布过文章分析&#xff1a;现在的云手机只是一个云端应用&#xff0c;并不是真正的云手机。需要在手机或电脑…

java 柱状图 宽度_Java实现 LeetCode 84 柱状图中最大得矩形

84. 柱状图中最大的矩形给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。以上是柱状图的示例&#xff0c;其中每个柱子的宽度为 1&#xff0c;给定的高度为…

java中为什么要用注解_java中的注解,真的很重要,你理解了嘛?

这篇文章开始讲解java中的注解&#xff0c;在平时的开发当中我相信你或多或少的接触过注解。比如你可能都见过override&#xff0c;它代表的就是一个注解。但是&#xff0c;为了更加清晰的去介绍注解&#xff0c;我还是先给出一个例子&#xff0c;让你能够方便的理解。一、认识…

qtdesigner右击按钮没有 to slot_或添加“力感按钮”再升级,Apple Pencil会更“能打”?...

&#xff3b;钉科技编译&#xff3d;“I have a pen/I have an apple/Ah apple pen”&#xff0c;钉科技编辑写到的这些“歌词”&#xff0c;看上去是不是很熟悉&#xff1f;对了&#xff0c;这是搞笑艺人Piko Taro那支颇“洗脑”的《PPAP》里的内容。其实&#xff0c;如果说到…

java三级报名_java web 学习 --第四天(Java三级考试)

jsp内置对象 outout属性类型&#xff1a;JspWriter 作用域&#xff1a;page 作用&#xff1a;一个输出缓存流&#xff0c;向客户端浏览器输出信息JspWriter类中常用的方法和功能flush() 输出缓存区的数据close() 关闭输出流clearBuffer() 清除缓存区的数据&#xff0c;并把数据…

tlab java_浅析java中的TLAB

好久&#xff0c;好久....没有更博客了。这一次利用闲暇时间&#xff0c;来扯一下关于JVM中的TLAB。什么是TLAB&#xff1f;它是干什么的&#xff1f;咋们先抛开这个问题&#xff0c;一切的开始得从new对象到指针碰撞开始讲起。new对象与指针碰撞new对象怎么就出问题了呢&#…

选择排序算法流程图_常用排序算法之选择排序

前两天给大家分享了冒泡排序和插入排序(没关注的同学&#xff0c;可以关注后查看历史消息)&#xff0c;今天继续给大家分享另一种常用的排序算法--选择排序。选择排序选择排序和插入排序很相似&#xff0c;也区分已排序区间和未排序区间&#xff0c;选择排序是每次从未排序区间…

pygame小游戏代码_Py之pygame:有趣好玩——利用pygame库实现一个移动底座弹球的小游戏...

Py之pygame&#xff1a;有趣好玩——利用pygame库实现一个移动底座弹球的小游戏目录输出结果实现代码输出结果​实现代码# -*- coding: utf-8 -*-#Py之pygame&#xff1a;有趣好玩——利用pygame库实现一个移动底座弹球的小游戏import pygame as pg from pygame.locals import …

大白菜pe解锁bitlocker_微PE工具箱 v2.1 官方版,最好用的 Win10PE 系统

微PE工具箱 v2.1 – 最好用的WinPE装机维护工具&#xff01;WinPE工具箱&#xff0c;装机维护最得力的助手&#xff0c;最后救命稻草。化繁为简&#xff0c;小材大用&#xff0c;一键安装&#xff0c;极速启动。微PE工具箱&#xff0c;最好用的PE工具箱&#xff0c;没有之一。无…

java8用什么tomcat_Tomcat8+JDK8安装与配置

一&#xff0c;系统配置1.操作系统&#xff1a;win10 64位2.tomcat版本&#xff1a;Tomcat8 64位3.Java版本&#xff1a;JDK8 64位二&#xff0c;软件下载下载到本地后直接打开安装&#xff0c;修改存储目录&#xff0c;如图&#xff1a;2.2 Tomcat8下载&#xff0c;官网地址&…

谷歌离开游览器不触发_谷歌游览器

谷歌浏览器不错&#xff0c;可保存不同的账户&#xff0c;互相不干扰。有2个账号&#xff0c;工作账号和个人账号&#xff0c;泾渭分明&#xff0c;不会打架&#xff0c;管理账号。总经理管理公司人员&#xff0c;厂长管理工人&#xff0c;业务员要管理自己账号&#xff0c;管理…

vue保存图片到手机相册_手机照片误删了怎么找回?这三个方法轻松搞定,亲测有效...

手机照片误删了怎么找回&#xff1f;很多人在使用手机拍照时&#xff0c;都会出现拍好的照片不小心点击了删除等情况&#xff0c;比如去某个地方游玩&#xff0c;或者看到了某个特别的场景拍下来的时候不小心删除了&#xff0c;那就非常可惜了&#xff0c;那么如何找回手机中误…

vue if判断_VUE学习记录2

v-if、v-eles、v-else-if​ v-if用于条件判断&#xff0c;判断Dom元素是否显示。<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scal…

利用melendy插入参考文献_四苯基卟啉在改性磷酸锆层间的插入及荧光增强

一、摘要近年来&#xff0c;出于节约一次性能源的考虑&#xff0c;人们已经加大对太阳能等天然资源的利用&#xff0e;致力于模拟天然光合作用的研究&#xff0c;而光合作用中的捕光复合物又称为光子天线。光子天线中往往存在一种或几种猝灭剂&#xff0c;猝灭剂吸收光子后产生…

百度链接解析_【集合】百度分享链接解析的方法总结

请大家在使用所有方法之前请先查看菜单栏中的用前必看01在别人分享的链接前面加 http://pan.naifei.cc/? 然后放入浏览器就可以解析了。比如: http://pan.naifei.cc/?链接:https://pan.baidu.com/s/XXX 提取码:1234 复制这段内容后打开百度网盘手机App&#xff0c;操作更方…

table表头固定4种方法_在常见的3种工资条场景中,教你4种批量打印工资条的方法...

私信回复关键词【福利】~获取丰富办公资源&#xff0c;助你高效办公早下班&#xff01;打印工资条估计是财务老师的痛&#xff0c;要把一行行的数据&#xff0c;变成一条条的工资条。数据很多&#xff0c;表头很复杂。一个个复制粘贴&#xff1f;那是不可能的&#xff01;那怎么…

hbase java api最新版本_HBase基本命令与新版本Java API

简介有关HBase的安装可以参考hbase安装我们可以通过hbase shell和hbase数据库进行交互&#xff0c;也可以通过Java-api和hbase数据库交互&#xff0c;这里我们使用的是hbase-client。主要是介绍2.0重大重构之后的api的基本使用。命名空间#列出所有命名空间list_namespace#新建命…