From 8fe122ce00418e5a35bb24cf8f3b8d16435efc38 Mon Sep 17 00:00:00 2001 From: AC_Oier Date: Tue, 25 Jan 2022 07:16:51 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8update:=20Modify=202045?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...10\345\233\260\351\232\276\357\274\211.md" | 74 ++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git "a/LeetCode/2041-2050/2045. \345\210\260\350\276\276\347\233\256\347\232\204\345\234\260\347\232\204\347\254\254\344\272\214\347\237\255\346\227\266\351\227\264\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/2041-2050/2045. \345\210\260\350\276\276\347\233\256\347\232\204\345\234\260\347\232\204\347\254\254\344\272\214\347\237\255\346\227\266\351\227\264\357\274\210\345\233\260\351\232\276\357\274\211.md" index 46a9c0ea..04f5b95f 100644 --- "a/LeetCode/2041-2050/2045. \345\210\260\350\276\276\347\233\256\347\232\204\345\234\260\347\232\204\347\254\254\344\272\214\347\237\255\346\227\266\351\227\264\357\274\210\345\233\260\351\232\276\357\274\211.md" +++ "b/LeetCode/2041-2050/2045. \345\210\260\350\276\276\347\233\256\347\232\204\345\234\260\347\232\204\347\254\254\344\272\214\347\237\255\346\227\266\351\227\264\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -78,7 +78,7 @@ Tag : 「最短路」、「BFS」、「堆优化 Dijkstra」 对「堆优化 Dijkstra」或者「其他最短路算法」不熟悉的同学,可以看前置 🧀 :[【最短路/必背模板】涵盖所有的「存图方式」与「最短路算法(详尽注释)」](https://mp.weixin.qq.com/s?__biz=MzU4NDE3MTEyMA==&mid=2247488007&idx=1&sn=9d0dcfdf475168d26a5a4bd6fcd3505d&chksm=fd9cb918caeb300e1c8844583db5c5318a89e60d8d552747ff8c2256910d32acd9013c93058f&token=211780171&lang=zh_CN#rd)。内容如题,首次接触的话,建议每个模板先敲十遍。 -回到本题,与常规的「求最短路」不同,本题需要求得「严格次短路」,我们可以原来的最短路算法基础上($dist1[]$ 数组用于记录最短路)多引入一个 $dist2[]$ 数组,$dist2[x]$ 用于记录从节点 $1$ 到节点 $x$ 的严格次短路。 +回到本题,与常规的「求最短路」不同,本题需要求得「严格次短路」,我们可以在原来的最短路算法基础上($dist1[]$ 数组用于记录最短路)多引入一个 $dist2[]$ 数组,$dist2[x]$ 用于记录从节点 $1$ 到节点 $x$ 的严格次短路。 维护次短路是容易的,基本思路为: @@ -93,7 +93,7 @@ Tag : 「最短路」、「BFS」、「堆优化 Dijkstra」 * $\left \lfloor \frac{step}{change} \right \rfloor$ 为偶数:当前处于绿灯,动态边权为 $0$; * $\left \lfloor \frac{step}{change} \right \rfloor$ 为奇数:当前处于红灯,需要增加动态边权(等待时间),增加的动态边权为 `change - (step % change)`。 -最后,为了避免每个样例都 `new` 大数组,我们可以使用 `static` 修饰需要用到的数据,并在执行逻辑前进行重置工作。 +最后,为了避免每个样例都 `new` 大数组,我们可以使用 `static` 修饰需要用到的数组,并在执行逻辑前进行重置工作。 代码: ```Java @@ -208,6 +208,76 @@ class Solution { --- +### AStar 算法 + +在 `BFS` 的基础上再进一步,我们可以将问题拓展为「使用 AStar 算法来找第 `K` 短路」(修改代码的 `K` 即可),利用终点的第 $k$ 次出队必然是第 $k$ 短路(注意要求的是严格的第 $k$ 短路)。 + +代码: +```Java +class Solution { + static int N = 10010, M = 4 * N, INF = 0x3f3f3f3f, K = 2, idx = 0, n = 0; + static int[] he = new int[N], e = new int[M], ne = new int[M]; + static int[] dist = new int[N]; + void add(int a, int b) { + e[idx] = b; + ne[idx] = he[a]; + he[a] = idx; + idx++; + } + void bfs() { + Arrays.fill(dist, INF); + Deque d = new ArrayDeque<>(); + d.addLast(n); + dist[n] = 0; + while (!d.isEmpty()) { + int x = d.pollFirst(), step = dist[x]; + for (int i = he[x]; i != -1; i = ne[i]) { + int j = e[i]; + if (dist[j] != INF) continue; + dist[j] = step + 1; + d.addLast(j); + } + } + } + int astar() { + int k = K, min = -1; + PriorityQueue q = new PriorityQueue<>((a,b)->a[2]-b[2]); + q.add(new int[]{1, 0, dist[1]}); + while (!q.isEmpty()) { + int[] poll = q.poll(); + int x = poll[0], step = poll[1]; + if (x == n && min != step) { + min = step; + if (--k == 0) return min; + } + for (int i = he[x]; i != -1; i = ne[i]) { + int j = e[i]; + q.add(new int[]{j, step + 1, step + 1 + dist[j]}); + } + } + return -1; // never + } + public int secondMinimum(int _n, int[][] edges, int time, int change) { + n = _n; idx = 0; + Arrays.fill(he, -1); + for (int[] e : edges) { + int u = e[0], v = e[1]; + add(u, v); add(v, u); + } + bfs(); + int cnt = astar(), ans = 0; + for (int i = 0; i < cnt; i++) { + int a = ans / change, b = ans % change; + int wait = a % 2 == 0 ? 0 : change - b; + ans += time + wait; + } + return ans; + } +} +``` + +--- + ### 最后 这是我们「刷穿 LeetCode」系列文章的第 `No.2045` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。