• 5905. 到达目的地的第二短时间


    题目

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

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

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

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

    注意:

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

    示例 1:

    输入:n = 5, edges = [[1,2],[1,3],[1,4],[3,4],[4,5]], time = 3, change = 5
    输出:13
    解释:
    上面的左图展现了给出的城市交通图。
    右图中的蓝色路径是最短时间路径。
    花费的时间是:

    • 从节点 1 开始,总花费时间=0
    • 1 -> 4:3 分钟,总花费时间=3
    • 4 -> 5:3 分钟,总花费时间=6
      因此需要的最小时间是 6 分钟。

    右图中的红色路径是第二短时间路径。

    • 从节点 1 开始,总花费时间=0
    • 1 -> 3:3 分钟,总花费时间=3
    • 3 -> 4:3 分钟,总花费时间=6
    • 在节点 4 等待 4 分钟,总花费时间=10
    • 4 -> 5:3 分钟,总花费时间=13
      因此第二短时间是 13 分钟。

    示例 2:

    输入:n = 2, edges = [[1,2]], time = 3, change = 2
    输出:11
    解释:
    最短时间路径是 1 -> 2 ,总花费时间 = 3 分钟
    最短时间路径是 1 -> 2 -> 1 -> 2 ,总花费时间 = 11 分钟

    提示:

    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

    BFS

    力扣上的最短路径问题基本上都可以用BFS解决。BFS的队列中我们存两个信息:

    1. 节点id
    2. 到当前节点的时间
      这里有两个问题需要处理:
    • 红绿灯等待问题
    • 找的不是最短路;而是第二短的路
      第一个问题很好解决: 我们知道所有节点都是从绿灯开始,以同样的周期进行红绿灯的交替变换。 如果当前时间为 t, 一共经历了 t / change 次变化;则 t / change % 2 == 1 则为红灯, 否则为绿灯。如果当前为红灯,我们需要将时间向上取整到当前红灯结束再入队即可。

    第二个问题就更简单了,记录多条路径即可。一般的权一样的最短路问题,BFS第一次搜索到终点,即找到了答案。这次我们求第二短的路,记录第二次搜索到的路径即可。可以用两个变量标记一下最短的两条路。因为严格最短,我们需要记录一下具体的值而不是出现次数。同样,一个路径如果经过了两次,我们也不用再把后面的路径加到队列中了。

        //fast用来记录最快到达某节点的时间,second用来记录次快到达某节点的时间
        //这两个变量和循环终止条件有关。如果没有这两个变量那么会出现死循环,因为可以任意穿过某个节点,会有源源不断的节点入队。
        //那么终止条件是什么呢?即假设当前位置为pos,如果到达该位置最快和次快的时间都找到了,那么这个节点就没有必要再入队了。
        private Map<Integer,Integer> fast=new HashMap<>();
        private Map<Integer,Integer> second=new HashMap<>();
        public int secondMinimum(int n, int[][] edges, int time, int change) {
            //将Map来存储图,可以快速找到相邻节点
            Map<Integer,List<Integer>> G=new HashMap<>();
            Queue<List<Integer>> Q=new LinkedList<>();
            for(int[] edge:edges){
                if(!G.containsKey(edge[0])) G.put(edge[0],new ArrayList<Integer>());
                if(!G.containsKey(edge[1])) G.put(edge[1],new ArrayList<Integer>());
                G.get(edge[0]).add(edge[1]);
                G.get(edge[1]).add(edge[0]);
            }
            Q.offer(Arrays.asList(1,0));
            //用来找次快路径
            int first=-1;
            while(!Q.isEmpty()){
                List<Integer> list=Q.poll();
                int node=list.get(0);
                int curTime=list.get(1);
                for(int next:G.get(node)){
                    int targetTime=curTime+time;
                    if(next==n){
                        //第一次找到最快路径
                        if(first==-1) first=targetTime;
                        //找到次快路径
                        else if(first<targetTime) return targetTime;
                    }
                    //遇到红灯
                    if((targetTime/change)%2==1){
                        targetTime=(targetTime/change+1)*change;
                    }
                    //第一次找到next节点的最快路径
                    if(!fast.containsKey(next)){
                        fast.put(next,targetTime);
                        Q.offer(Arrays.asList(next,targetTime));
                    }
                    //第一次找到next节点的次快路径
                    else if(!second.containsKey(next)&&fast.get(next)<targetTime){
                        second.put(next,targetTime);
                        Q.offer(Arrays.asList(next,targetTime));
                    }
                }
            }
            return -1;
        }
    

    参考:https://leetcode-cn.com/problems/second-minimum-time-to-reach-destination/solution/wei-rao-li-lun-bfsji-lu-dao-di-er-duan-d-z67m/
    原题链接:https://leetcode-cn.com/problems/second-minimum-time-to-reach-destination

  • 相关阅读:
    做一个:网页请求数据库数据 流程
    开始一个Django项目的简单方法
    Django模板系统
    Python Django 中的STATIC_URL 设置和使用解析
    Django框架(一)-Django初识
    bootstrap
    jQuery
    js(jquery)鼠标移入移出事件时,出现闪烁、隐藏显示隐藏显示不停切换的情况
    PHPCMS快速建站系列之网站迁移(本地到服务器,服务器迁移,更换域名等)
    PHPCMS快速建站系列之在线留言
  • 原文地址:https://www.cnblogs.com/Frank-Hong/p/15418617.html
Copyright © 2020-2023  润新知