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
  给你 nedgestimechange,返回从节点 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、原题链接

LeetCode 2045. 到达目的地的第二短时间

二、解题报告

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]”

leetcode 789. 逃脱阻碍者

55. 跳跃游戏-LeetCode

LeetCode 1154 一年中的第几天[数组] HERODING的LeetCode之路

LeetCode 19删除链表的倒数第N个节点

题解luogu2045 方格取数游戏加强版