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

难度:困难

目录

一、问题描述

二、解题思想

三、解题

1、判断极端情况

2、代码实现

四、总结


一、问题描述

这里直接采用的是LeetCode上面的问题描述。

        城市用一个 双向连通 图表示,图中有 n 个节点,从 1 n 编号(包含 1 n)。图中的边用一个二维整数数组 edges 表示,其中每个 edges[i] = [ui, vi] 表示一条节点 ui 和节点 vi 之间的双向连通边。每组节点对由 最多一条 边连通,顶点不存在连接到自身的边。穿过任意一条边的时间是 time 分钟。

        每个节点都有一个交通信号灯,每 change 分钟改变一次,从绿色变成红色,再由红色变成绿色,循环往复。所有信号灯都 同时 改变。你可以在 任何时候 进入某个节点,但是 只能 在节点 信号灯是绿色时 才能离开。如果信号灯是 绿色 ,你 不能 在节点等待,必须离开。

第二小的值 是 严格大于 最小值的所有值中最小的值。

  • 例如,[2, 3, 4] 中第二小的值是 3 ,而 [2, 2, 4] 中第二小的值是 4 。给你 nedgestime change ,返回从节点 1 到节点 n 需要的 第二短时间

注意:

  • 你可以 任意次 穿过任意顶点,包括 1 n
  • 你可以假设在 启程时 ,所有信号灯刚刚变成 绿色

下面给出示例:

提示:

  • 2 <= n <= 104
  • n - 1 <= edges.length <= min(2 * 104, n * (n - 1) / 2)
  • edges[i].length == 2
  • 1 <= ui, vi <= n
  • ui != vi
  • 不含重复边
  • 每个节点都可以从其他节点直接或者间接到达
  • 1 <= time, change <= 103

 

二、解题思想

        首先看到这题,关于图的最小路径,首先想到的就是DFS以及BFS。但是这一题不是求图的最短路径而是求图的 次短路径 的 时间。和之前的1345.跳跃游戏IV-LeetCode有异曲同工之妙,那一题是求到最后一个节点的最短路径,此题是求 次短路径时间

        这里需要注意的是题目中说了:你可以 任意次 穿过任意顶点,包括 1 和 n 。意思就是可以回头穿过源点,再去走目标节点。意思为下图,当节点为 2 时,需要穿过源点一次此时为 次短路径

 

        我们依然可以用BFS,在这里需要维护一个从源点到其他节点的最短路径和 次短路径 的表。

使用BFS之前要做的准备:

  1. 初始化vector<vector<int>> path(n+1, vector<int>(2, INT_MAX))  ( path[i][0] 存放从源点到i节点的 最短路径长度,path[i][1] 存放从源点到 i 节点的 严格次短路径长度 )。将path[1][0] 的距离设置为 0
  2. 定义队列 queue<pair<int, int>> Q (队列 Q{ i, j } 用来存储源点到节点 i 的 路程 j)。入队{1,0}从源点开始 BFS

BFS需要进行的操作:

  1. 判断 源点当前节点的路径 是否 严格小于 最小路径,维护最短路径path[i,0]。( i 为当前BFS的节点)
  2. 判断 源点当前节点的路径 是否 严格大于 最小路径 且 严格小于 次短路径 ,维护次短路径path[i][1]。( i 为当前BFS的节点)     

        最后要进行将 次短路径 转换为次短时间。由于刚起始是绿灯,那么每过 2*change 又是绿灯;则只有在当前节点 的时间处于 :ans % (2 * change) >= change  那么就需要等待的时间为:(2 * change - ans % (2 * change)) 。 

三、解题

1、判断极端情况

        这里使用BFS不需要判断极端情况最少传入两个节点。

2、代码实现

class Solution {
public:
    int secondMinimum(int n, vector<vector<int>>& edges, int time, int change) {
        //用零阶矩阵 将无向图抽象出来 
        vector<vector<int>> Graphs(n+1);
        for(auto& item: edges){
            Graphs[item[0]].push_back(item[1]);
            Graphs[item[1]].push_back(item[0]);
        }
        // path[i][0] 存放从源点到i节点的 最短路径长度,path[i][1] 存放从源点到i节点的 严格次短路径长度
        vector<vector<int>> path(n+1, vector<int>(2, INT_MAX));
        path[1][0] = 0;
        //队列 Q{ i, j } 用来存储源点到节点 i 的 路程 j
        queue<pair<int, int>> Q;
        //初始化从节点1 开始BFS
        Q.push({1,0});
        //使用BFS  一直计算从源点 到各节点的 最小以及次小路径 当有了目的节点的次小路径之后 停止循环
        while(path[n][1] == INT_MAX){
            //p用来保存 源点到节点 i 的 路程 j 
            auto p = Q.front();
            Q.pop();
            //bfsNode 为每一轮广度搜索到达的节点 更新 从原点到达bfsNode节点 的 最小及次小路径
            for(auto bfsNode : Graphs[p.first]){
                //如果从源点到达bfsNode 的路径 小于当前最小路径 那么更新此最小路径
                if(p.second + 1 < path[bfsNode][0]){
                    path[bfsNode][0] = p.second + 1;
                    Q.push({bfsNode, p.second + 1});
                }
                //如果从源点到达bfsNode 的路径 严格大于最小路径 并且严格小于当前次小路径 那么更新此次小路径
                if(p.second + 1 > path[bfsNode][0] && p.second + 1 < path[bfsNode][1]){
                    path[bfsNode][1] = p.second + 1;
                    Q.push({bfsNode, p.second + 1});
                }
            }
        }
        int ans = 0;
        //刚起始是绿灯,每过 2*change 又是绿灯
        //ans是当前总时间 ans %(2*change) >= change 则是需要等待的时间 小于则不需要等待
        //(2 * change -  ans % (2 * change )) 则是需要等待的时间
        for(int i = 0; i < path[n][1]; i++){
            if(ans % (2 * change) >= change){
                ans += (2 * change - ans % (2 * change));
            }
            ans += time;
        }
        return ans;
    }
};

四、总结

        刚开始看到题目,是懵逼的(基础比较薄弱),然后在分析题解一步步将题解拆开看,开始没有弄明白 队列中 pair 参数的意思,瞎琢磨了很久,后面可以将无向图想象成双向图,只要没有找到次短路径 那么就一直BFS以增加路径长度,直至找到 次短路径 为止。

        注释都很详细,如果对你有什么帮助,请star ♥ 一下,收藏一下,蟹蟹啦!👇👇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Alkaid_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值