列表

详情


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

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

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

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

给你 nedgestimechange ,返回从节点 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 分钟

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int secondMinimum(int n, vector<vector<int>>& edges, int time, int change) { } };

golang 解法, 执行用时: 332 ms, 内存消耗: 8.7 MB, 提交时间: 2023-09-17 12:08:24

const inf int = 0x3f3f3f3f
func secondMinimum(n int, edges [][]int, time int, change int) (ans int) {
    graph := map[int][]int{}
    for _, edge := range edges{
        graph[edge[0] - 1] = append(graph[edge[0] - 1], edge[1] - 1)
        graph[edge[1] - 1] = append(graph[edge[1] - 1], edge[0] - 1)
    }
    explored := make([][]int, n)
    for i := 0; i < n; i++{
        explored[i] = []int{inf, inf}
    }
    explored[0][0] = 0
    queue := [][]int{{0, 0}}
    out:
    for len(queue) > 0{
        idx, dist := queue[0][0], queue[0][1]
        queue = queue[1:]
        for _, other := range graph[idx]{
            if explored[other][0] > dist + 1{
                explored[other][0] = dist + 1
            } else if explored[other][0] < dist + 1 && explored[other][1] > dist + 1{
                explored[other][1] = dist + 1
                if other == n - 1{
                    break out
                }
            } else{
                continue
            }
            queue = append(queue, []int{other, dist + 1})
        }
    }
    for i := 0; i < explored[n - 1][1]; i++ {
        ans += time
        if i < explored[n-1][1] - 1 && (ans / change) % 2 == 1{
            ans = (ans + change)/change * change
        }
    }
    return
}

javascript 解法, 执行用时: 256 ms, 内存消耗: 66.8 MB, 提交时间: 2023-09-17 12:08:00

/**
 * @param {number} n
 * @param {number[][]} edges
 * @param {number} time
 * @param {number} change
 * @return {number}
 */
const INF = 0x3f3f3f3f
var secondMinimum = function(n, edges, time, change) {
    const graph = new Array(n).fill(0).map(() => new Array());
    for (const edge of edges) {
        graph[edge[0] - 1].push(edge[1] - 1);
        graph[edge[1] - 1].push(edge[0] - 1);
    }
    const explored = new Array(n).fill(0).map(() => new Array(2).fill(INF))
    let queue = [0], dist = 0
    out:
    while(queue.length > 0){
        dist += 1
        const nxt = new Array()
        for(const idx of queue)
            for(const other of graph[idx]){
                if(explored[other][0] > dist)
                    explored[other][0] = dist
                else if(explored[other][0] < dist && explored[other][1] > dist){
                    explored[other][1] = dist
                    if(other == n - 1)
                        break out
                }
                else
                    continue
                nxt.push(other)
            }
        queue = nxt
    }
    let ans = 0
    for(let i = 0; i < explored[n-1][1]; i++){
        ans += time
        if(i < explored[n-1][1] -1 && Math.floor(ans/change) % 2 == 1)
            ans = Math.floor((ans + change)/change) * change
    }
    return ans
};

java 解法, 执行用时: 81 ms, 内存消耗: 54.5 MB, 提交时间: 2023-09-17 12:07:43

class Solution {
    private static final int INF = 0x3f3f3f3f;
    public int secondMinimum(int n, int[][] edges, int time, int change) {
        Map<Integer, List<Integer>> graph = new HashMap<>();
        for(int[] edge: edges){
            List<Integer> a = graph.getOrDefault(edge[0] - 1, new ArrayList<>());
            List<Integer> b = graph.getOrDefault(edge[1] - 1, new ArrayList<>());
            a.add(edge[1] - 1);
            b.add(edge[0] - 1);
            graph.put(edge[0] - 1, a);
            graph.put(edge[1] - 1, b);
        }
        int[][] explored = new int[n][2];
        for(int i=0;i<n;i++)
            Arrays.fill(explored[i], INF);
        Deque<int[]> queue = new ArrayDeque<>();
        queue.addLast(new int[]{0, 0});
        explored[0][0] = 0;
        out:
        while(!queue.isEmpty()){
            int[] cur = queue.pollFirst();
            int idx = cur[0], nxtDist = cur[1] + 1;
            for(int other: graph.get(idx)){
                if(nxtDist < explored[other][0])
                    explored[other][0] = nxtDist;
                else if(nxtDist > explored[other][0] && nxtDist < explored[other][1]){
                    explored[other][1] = nxtDist;
                    if(other == n - 1)
                        break out;
                }
                else
                    continue;
                queue.addLast(new int[]{other, nxtDist});
            }
        }
        int ans = 0;
        for(int i=0;i<explored[n-1][1];i++){
            ans += time;
            if(i < explored[n-1][1] - 1 && (ans / change) % 2 == 1)
                ans = (ans + change) / change * change; 
        }
        return ans;
    }
}

python3 解法, 执行用时: 504 ms, 内存消耗: 27 MB, 提交时间: 2023-09-17 12:07:29

'''
由于time和change是固定的,而不是在不同边有不同的值,
所以我们可以统计出起点到终点的最短距离和次短距离,然后根据次短距离计算答案。
'''
class Solution:
    def secondMinimum(self, n: int, edges: List[List[int]], time: int, change: int) -> int:
        graph = defaultdict(set)
        for a,b in edges:
            graph[a].add(b)
            graph[b].add(a)
        # idx, dist
        pq = deque([(1, 0)])
        explored = [[inf] * 2 for _ in range(n)]
        explored[0][0] = 0
        while pq:
            idx, dist = pq.popleft()
            for other in graph[idx]:
                if dist + 1 < explored[other - 1][0]:
                    explored[other - 1][0] = dist + 1
                elif explored[other - 1][0] < dist + 1 < explored[other - 1][1]:
                    explored[other - 1][1] = dist + 1
                    if other == n:
                        ans = 0
                        for i in range(explored[-1][1]):
                            ans += time
                            if i < explored[-1][1] - 1 and (ans // change) % 2:
                                ans = (ans + change) // change * change
                        return ans
                else:
                    continue
                pq.append((other, dist + 1))
        return -1

golang 解法, 执行用时: 268 ms, 内存消耗: 9.5 MB, 提交时间: 2023-09-17 12:06:47

/**
 * 简单说一下为什么可以用 BFS。由于 time\ 和 change 是固定的,
 * 经过多少条边就知道花费了多少时间。因此这题本质上可以看成边权均为 1 的图,
 * 我们要求的就是 1 到 n 的严格次短路的长度,知道长度就知道花费的时间。
 * 下面的代码是直接用 BFS 求次短时间。
 */
func secondMinimum(n int, edges [][]int, time, change int) int {
	g := make([][]int, n)
	for _, e := range edges { // 建图
		v, w := e[0]-1, e[1]-1
		g[v] = append(g[v], w)
		g[w] = append(g[w], v)
	}

	// 传入当前时间 d,返回到达下一个节点的时间
	next := func(d int) int {
		if times := d / change; times%2 == 1 { // 如果红绿灯切换次数为奇数,则现在是红灯
			return (times+1)*change + time // 等绿灯再出发
		}
		return d + time // 绿灯,直接出发
	}

	dis := make([][2]int, n) // 距离数组同时存 [最短路, 次短路]
	dis[0][1] = 1e9
	for i := 1; i < n; i++ {
		dis[i] = [2]int{1e9, 1e9}
	}
	type pair struct{ v, d int }
	q := []pair{{}}
	for len(q) > 0 { // BFS 求最短路和次短路
		p := q[0] // 取队首
		q = q[1:]
		for _, w := range g[p.v] {
			d := next(p.d) // 到达节点 w 的时间
			if d < dis[w][0] { // d 比最短路小,就更新最短路
				dis[w][0] = d
				q = append(q, pair{w, d})
			} else if dis[w][0] < d && d < dis[w][1] { // d 比最短路大又比次短路小,就更新次短路
				dis[w][1] = d
				q = append(q, pair{w, d})
			}
		}
	}
	return dis[n-1][1]
}

上一题