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

本文介绍了一道LeetCode上的题目,要求求解从起点到终点的次短时间。通过对给定边信息构建图,并利用BFS算法,实现对每个节点最短路径和次短路径的记录。最后详细解释了如何根据次短路径计算次短时间。

题目来源:https://leetcode-cn.com/problems/second-minimum-time-to-reach-destination/

大致题意:
给定一个整数 n (从 1 开始编号)表示节点数,一个 edges 数组表示相连的边,一个 time 表示每次移动需要花费的时间,一个 change 表示节点状态的持续时间(节点有两种状态:通行和停止,移动到通行状态的节点必须继续移动,移动到停止状态的节点不能移动,两种状态交替变化,初始时是通行状态)

求出从节点 1 到节点 n 需要花的次短时间(严格大于最短时间)

思路

求权重相同的最短路径问题可以用 BFS

与常规 BFS 不同,该题是求次短路径,而且也允许同一个节点多次访问,那么在 BFS 过程中,加入队列节点的判断方法应该有所改变:

  • 使用一个二维数组存下到达每个节点最短路径和次短路径,初始时都为 int 的最大值
  • 每次从队列取出节点后,在能到达的节点中寻找从当前位置走过去的距离比已有的距离更短的节点,可以使最短也可以是次短,如果有就放入队列

找到次短路径后,就可以通过给定的 time 和 change 计算出次短时间(因为所有节点状态同时变化,所以次短路径一定对应次短时间)

次短时间的计算方法:

  • 判断走到当前节点时,是否是停止状态。令当前时间是 t,那么可以通过 t % (change * 2) >= change来判断
  • 若是通行状态,直接加上 time
  • 若是停止状态,加上需要等待的时间 change * 2 - t % (change * 2)
BFS
  1. 将给定的边的信息处理成图
  2. 初始化节点对应的路径数组
  3. BFS 找出次短路径
  4. 计算次短时间
public int secondMinimum(int n, int[][] edges, int time, int change) {
        // 1. 将给定的边的信息处理成图
        List<Integer>[] graph = new List[n + 1];
        for (int i = 0; i <= n; i++) {
            graph[i] = new ArrayList<>();
        }
        int m = edges.length;
        for (int i = 0; i < m; i++) {
            graph[edges[i][0]].add(edges[i][1]);
            graph[edges[i][1]].add(edges[i][0]);
        }
        Queue<int[]> queue = new ArrayDeque<>();
        queue.offer(new int[]{1, 0});
        // 2. 初始化节点对应的路径数组
        int[][] len = new int[n + 1][2];
        for (int i = 0; i <= n; i++) {
            len[i][0] = Integer.MAX_VALUE;
            len[i][1] = Integer.MAX_VALUE;
        }
        len[1][0] = 0;
        // 3. BFS 找出次短路径
        while (len[n][1] == Integer.MAX_VALUE) {
            int[] arr = queue.poll();
            int node = arr[0];
            int step = arr[1] + 1;
            // 遍历当前点可以到达的点
            for (int i = 0; i < graph[node].size(); i++) {
                int next = graph[node].get(i);
                // 如果从当前点去该点的距离小于已有的最短路径,更新
                if (len[next][0] > step) {
                    queue.offer(new int[]{next, step});
                    len[next][0] = step;
                } else if (step > len[next][0] && step < len[next][1]) {
                    // 如果从当前点去该点的距离小于已有的次短路径,更新
                    queue.offer(new int[]{next, step});
                    len[next][1] = step;
                }
            }
        }

        // 4. 计算次短时间
        int ans = 0;
        for (int i = 0; i < len[n][1]; i++) {
            // 判断是否需要等待
            boolean turn = ans % (2 * change) >= change;
            if (turn) {
                // 加上等待时间
                ans += 2 * change - ans % (2 * change);
            }
            // 加上本次移动耗时
            ans += time;
        }
        return ans;
    }
到达目的地的方案数 时间限制: 1s 类别: DS:图->力扣 问题描述 你在一个城市里,城市由 n 个路口组成,路口编号为 0 到 n - 1 ,某些路口之间有 双向 道路。输入保证你可以从任意路口出发到达其他任意路口,且任意两个路口之间多有一条路。 给你一个整数 n 和二维整数数组 roads ,其中 roads[i] = [ui, vi, timei] 表示在路口 ui 和 vi 之间有一条需要花费 timei 时间才能通过的道路。你想知道花费 少时间 从路口 0 出发到达路口 n - 1 的方案数。 请返回花费少时间到达目的地的路径数目 。由于答案可能很大,将结果对 10^9 + 7 取余 后返回。 示例 1: n = 7, roads = [[0,6,7],[0,1,2],[1,2,3],[1,3,3],[6,3,3],[3,5,1],[6,5,1],[2,5,1],[0,4,5],[4,6,2]] 输入: 7 10 0 6 7 0 1 2 1 2 3 1 3 3 6 3 3 3 5 1 6 5 1 2 5 1 0 4 5 4 6 2 输出:4 解释:从路口 0 出发到路口 6 花费的少时间是 7 分钟。 四条花费 7 分钟的路径分别为: - 0 ➝ 6 - 0 ➝ 4 ➝ 6 - 0 ➝ 1 ➝ 2 ➝ 5 ➝ 6 - 0 ➝ 1 ➝ 3 ➝ 5 ➝ 6 示例 2: n = 2, roads = [[1,0,10]] 输入: 2 1 1 0 10 输出:1 解释:只有一条从路口 0 到路口 1 的路,花费 10 分钟。 输入说明 第一行先输入一个n和m,表示n个路口,m条路(即roads数组的行数) 接下来m行,每行三个整数,表示一条路的信息roads[i],即 [ui, vi, timei] 提示: 1 <= n <= 200 n - 1 <= m <= n * (n - 1) / 2 0 <= ui, vi <= n - 1 1 <= timei <= 10^9 ui != vi 任意两个路口之间至多有一条路。 从任意路口出发,你能够到达其他任意路口。 输出说明 输出一个整数,表示花费少时间到达目的地的路径数目 。由于答案可能很大,将结果对 10^9 + 7 取余后输出 输入范例 7 10 0 6 7 0 1 2 1 2 3 1 3 3 6 3 3 3 5 1 6 5 1 2 5 1 0 4 5 4 6 2 输出范例 4
05-29
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

三更鬼

谢谢老板!

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

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

打赏作者

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

抵扣说明:

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

余额充值