Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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$ 的严格次短路。

维护次短路是容易的,基本思路为:

Expand All @@ -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
Expand Down Expand Up @@ -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<Integer> 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<int[]> 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 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
Expand Down