### 描述
-设 $d_i$ 表示起点 $s到点i$ 的最短路长度。初始时 $d_s = 0$,其他都设为无穷大。
+设 $d_i$ 表示起点 $s到点i$ 的最短路长度。初始时 $d_s = 0$ ,其他都设为无穷大。
设 $p_i$ 表示点 i 在最短路树上的父亲。
维护三个点集:
-- $M_0$ - 已经计算出距离的点(即便不是最短距离);
-- $M_1$ - 正在计算距离的点;
-- $M_2$ - 还没被计算距离的点。
+- $M_0$ - 已经计算出距离的点(即便不是最短距离);
+- $M_1$ - 正在计算距离的点;
+- $M_2$ - 还没被计算距离的点。
点集 $M_1$ 将采用双向队列来存储。
每次我们从 $M_1$ 中取一个点 $u$ ,然后将点 $u$ 存入 $M_0$ 。然后我们遍历从 $u$ 出发的所有边。设另一端是点 $v$ ,权值为 $w$ :
-- 如果 $v \in M_2$,将 $v$ 插入 $M_1$ 队尾, 并更新 $d_v:d_v\gets d_u + w$ 。
-- 如果 $v \in M_1$,那我们就更新 $d_v$ : $d_v = \min(d_v, d_u + w)$ 。
-- 如果 $v \in M_0$,并且 $d_v$ 可以被改进到 $d_v > d_u + w$,那么我们就更新 $d_v$ ,并将 $v$ 插入到 $M_1$ 的队首。
+- 如果 $v \in M_2$ ,将 $v$ 插入 $M_1$ 队尾,并更新 $d_v:d_v\gets d_u + w$ 。
+- 如果 $v \in M_1$ ,那我们就更新 $d_v$ : $d_v = \min(d_v, d_u + w)$ 。
+- 如果 $v \in M_0$ ,并且 $d_v$ 可以被改进到 $d_v > d_u + w$ ,那么我们就更新 $d_v$ ,并将 $v$ 插入到 $M_1$ 的队首。
当然,每次更新数组 $d$ 时,我们也必须更新 $p$ 数组中相应的元素。
??? note "参考代码"
```cpp
struct Edge {
- int to, w;
+ int to, w;
};
int n;
vector<vector<Edge>> adj;
const int INF = 1e9;
void shortest_paths(int v0, vector<int>& d, vector<int>& p) {
- d.assign(n, INF);
- d[v0] = 0;
- vector<int> m(n, 2);
- deque<int> q;
- q.push_back(v0);
- p.assign(n, -1);
- while (!q.empty()) {
- int u = q.front();
- q.pop_front();
- m[u] = 0;
- for (Edge e : adj[u]) {
- if (d[e.to] > d[u] + e.w) {
- d[e.to] = d[u] + e.w;
- p[e.to] = u;
- if (m[e.to] == 2) {
- m[e.to] = 1;
- q.push_back(e.to);
- } else if (m[e.to] == 0) {
- m[e.to] = 1;
- q.push_front(e.to);
- }
- }
+ d.assign(n, INF);
+ d[v0] = 0;
+ vector<int> m(n, 2);
+ deque<int> q;
+ q.push_back(v0);
+ p.assign(n, -1);
+ while (!q.empty()) {
+ int u = q.front();
+ q.pop_front();
+ m[u] = 0;
+ for (Edge e : adj[u]) {
+ if (d[e.to] > d[u] + e.w) {
+ d[e.to] = d[u] + e.w;
+ p[e.to] = u;
+ if (m[e.to] == 2) {
+ m[e.to] = 1;
+ q.push_back(e.to);
+ } else if (m[e.to] == 0) {
+ m[e.to] = 1;
+ q.push_front(e.to);
}
+ }
}
+ }
}
```
比如 Floyd 就要记录 `pre[i][j] = k;` ,Bellman-Ford 和 Dijkstra 一般记录 `pre[v] = u` 。
-**本页面部分内容译自博文[Тернарный поиск](http://e-maxx.ru/algo/levit_algorithm)与其英文翻译版[D´Esopo-Pape algorithm](https://cp-algorithms.com/graph/desopo_pape.html)。其中俄文版版权协议为 Public Domain + Leave a Link;英文版版权协议为 CC-BY-SA 4.0。**
\ No newline at end of file
+ **本页面部分内容译自博文 [Тернарный поиск](http://e-maxx.ru/algo/levit_algorithm) 与其英文翻译版 [D´Esopo-Pape algorithm](https://cp-algorithms.com/graph/desopo_pape.html) 。其中俄文版版权协议为 Public Domain + Leave a Link;英文版版权协议为 CC-BY-SA 4.0。**