LeetCode 2045. 到达目的地的第二短时间
Posted 英雄哪里出来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 2045. 到达目的地的第二短时间相关的知识,希望对你有一定的参考价值。
文章目录
一、题目
1、题目描述
城市用一个 双向连通图 表示,图中有 n n n 个节点,从 1 1 1 到 n n n 编号(包含 1 1 1 和 n n n)。图中的边用一个二维整数数组
edges
表示,其中每个edges[i] = [ui, vi]
表示一条节点ui
和节点vi
之间的双向连通边。每组节点对由 最多一条边连通,顶点不存在连接到自身的边。穿过任意一条边的时间是time
分钟。
每个节点都有一个交通信号灯,每change
分钟改变一次,从绿色变成红色,再由红色变成绿色,循环往复。所有信号灯都同时改变。你可以在 任何时候 进入某个节点,但是 只能 在节点 信号灯是绿色时 才能离开。如果信号灯是 绿色 ,你 不能 在节点等待,必须离开。
第二小的值 是 严格大于 最小值 的所有值中最小的值。
例如,[2, 3, 4]
中第二小的值是3
,而[2, 2, 4]
中第二小的值是4
。
给你n
、edges
、time
和change
,返回从节点 1 1 1 到节点 n n n 需要的 第二短时间 。
注意:
你可以 任意次 穿过任意顶点,包括 1 1 1 和 n n n。
你可以假设在 启程时 ,所有信号灯刚刚变成 绿色。
样例输入:n = 5, edges = [[1,2],[1,3],[1,4],[3,4],[4,5]], time = 3, change = 5
样例输出:13
2、基础框架
- C++ 版本给出的基础框架代码如下:
class Solution
public:
int secondMinimum(int n, vector<vector<int>>& edges, int time, int change)
;
3、原题链接
二、解题报告
1、思路分析
1)要点分析
(
1
)
(1)
(1) 这个问题存在一个红灯、绿灯切换的问题。红灯是不能走的,需要等到下一个绿灯以后才能走。
(
2
)
(2)
(2) 求最短路问题,大概率是广度优先搜索。
(
3
)
(3)
(3) 求次短路问题,也是广度优先搜索,最短路记录的是最短路,次短路需要记录最短路和次短路。
(
4
)
(4)
(4) 每条边权重是一样的。
2)算法详解
(
1
)
(1)
(1) 对整个图建边(它是双向边)。
(
2
)
(2)
(2) 初始化从1
到所有点的最短路min[i] = inf
,次短路submin[i] = inf
;
(
3
)
(3)
(3) 初始化 1 到 1 的最短路为 min[1] = 0
,并且塞入队列;
(
4
)
(4)
(4) 循环迭代,从队列中取出一个结点u
:
(
4.1
)
(4.1)
(4.1) 如果 submin[n] != inf
,说明次短路找到了直接返回;
(
4.2
)
(4.2)
(4.2) min[u]/change
表示我的红绿灯改变了多少次,改变的次数只有两种情况:奇数 和 偶数,一开始绿灯,所以改变偶数次就还是绿灯,无需等待timewait = 0
;而改变奇数次,需要等待的时间为timewait = change - min[u]%change
;
(
4.3
)
(4.3)
(4.3) 对于每个和 u
相邻的点v
,从 1 -> ... -> u -> v
的最短路为 min[u] + time + timewait
,如果它比 min[v]
小,则用它来更新min[v]
,并且同时更新次短路,把v
塞入队列;
(
4.4
)
(4.4)
(4.4) 如果 从 1 -> ... -> u -> v
的最短路和 min[v]
相等则跳过本次判断;
(
4.5
)
(4.5)
(4.5) 如果 从 1 -> ... -> u -> v
的最短路比次短路 submin[v]
小,则更新次短路,把v
塞入队列;
(
5
)
(5)
(5) 然后,用次短路submin[u]
执行同样的更新。
2、时间复杂度
最坏时间复杂度 O ( n + m ) O(n + m) O(n+m) 。
3、代码详解
class Solution
#define maxn 10010
#define inf -1
vector <int> Edges[maxn];
int min[maxn];
int submin[maxn];
void init(int n)
for(int i = 1; i <= n; ++i)
Edges[i].clear();
memset(min, inf, sizeof(min));
memset(submin, inf, sizeof(submin));
bool smaller(int dist1, int dist2)
if(dist2 == inf) return true;
if(dist1 == inf) return false;
return dist1 < dist2;
void addEdge(int u, int v)
Edges[u].push_back(v);
Edges[v].push_back(u);
public:
int secondMinimum(int n, vector<vector<int>>& edges, int time, int change)
int i;
queue <int> q;
init(n);
for(i = 0; i < edges.size(); ++i)
addEdge(edges[i][0], edges[i][1]);
min[1] = 0;
q.push(1);
/**********************上面的代码确保准确无误**********************/
while(!q.empty())
int u = q.front();
q.pop();
if(submin[n] != inf)
return submin[n];
vector<int> p = min[u], submin[u];
for(int k = 0; k < p.size(); ++k)
int timered = (( p[k]/change ) & 1) ? ( change - p[k]%change ) : 0;
int dist = p[k] + time + timered;
if(p[k] == inf)
continue;
// (u -> v)
for(i = 0; i < Edges[u].size(); ++i)
int v = Edges[u][i];
if( smaller(dist, min[v]) )
submin[v] = min[v];
min[v] = dist;
q.push(v);
else if(dist == min[v])
continue;
else if(smaller(dist, submin[v]) )
submin[v] = dist;
q.push(v);
return -1;
;
三、本题小知识
次短路比最短路多存了一维的状态。
四、加群须知
相信看我文章的大多数都是「 大学生 」,能上大学的都是「 精英 」,那么我们自然要「 精益求精 」,如果你还是「 大一 」,那么太好了,你拥有大把时间,当然你可以选择「 刷剧 」,然而,「 学好算法 」,三年后的你自然「 不能同日而语 」。
那么这里,我整理了「 几十个基础算法 」 的分类,点击开启:
如果链接被屏蔽,或者有权限问题,可以私聊作者解决。
大致题集一览:
为了让这件事情变得有趣,以及「 照顾初学者 」,目前题目只开放最简单的算法 「 枚举系列 」 (包括:线性枚举、双指针、前缀和、二分枚举、三分枚举),当有 一半成员刷完 「 枚举系列 」 的所有题以后,会开放下个章节,等这套题全部刷完,你还在群里,那么你就会成为「 夜深人静写算法 」专家团 的一员。
不要小看这个专家团,三年之后,你将会是别人 望尘莫及 的存在。如果要加入,可以联系我,考虑到大家都是学生, 没有「 主要经济来源 」,在你成为神的路上,「 不会索取任何 」。
🔥联系作者,或者扫作者主页二维码加群,加入刷题行列吧🔥
🔥让天下没有难学的算法🔥
C语言免费动漫教程,和我一起打卡! 🌞《光天化日学C语言》🌞
让你养成九天持续刷题的习惯 🔥《九日集训》🔥
入门级C语言真题汇总 🧡《C语言入门100例》🧡
组团学习,抱团生长 🌌《算法零基础100讲》🌌
几张动图学会一种数据结构 🌳《画解数据结构》🌳
竞赛选手金典图文教程 💜《夜深人静写算法》💜
以上是关于LeetCode 2045. 到达目的地的第二短时间的主要内容,如果未能解决你的问题,请参考以下文章
ShellCheck 警告:“迭代 ls 输出很脆弱。使用 glob。[SC2045]”