跳转至

S-L14 最短路

覆盖词条:KS-61b/c/d | 先修:J-L19/S-L08/S-L03

模板与代码

Dijkstra(堆优化)

非负权单源最短路,复杂度 O((n+m)log n)。核心剪枝:弹出的状态若已过期(d > dist[u])直接跳过。

#include <bits/stdc++.h>
using namespace std;

const int64_t INF = numeric_limits<int64_t>::max() / 2;

// 堆优化 Dijkstra:非负权单源最短路,O((n + m) log n)
// n: 点数(0 ~ n-1),g: 邻接表 {to, w},s: 源点
vector<int64_t> dijkstra(int n, const vector<vector<pair<int, int>>>& g, int s) {
    vector<int64_t> dist(n, INF);
    priority_queue<pair<int64_t, int>, vector<pair<int64_t, int>>, greater<>> pq;
    dist[s] = 0;
    pq.emplace(0, s);
    while (!pq.empty()) {
        auto [d, u] = pq.top(); pq.pop();
        if (d > dist[u]) continue;         // 过期状态,跳过
        for (auto [v, w] : g[u]) {
            if (dist[u] + w < dist[v]) {
                dist[v] = dist[u] + w;
                pq.emplace(dist[v], v);
            }
        }
    }
    return dist;
}

Floyd-Warshall

多源最短路:一次求出所有点对之间的最短距离,可处理负边权(不允许负环),复杂度 O(n^3)、空间 O(n^2),适合 n <= 500 的稠密图。

#include <bits/stdc++.h>
using namespace std;

const int64_t INF = numeric_limits<int64_t>::max() / 2;

// Floyd-Warshall:多源最短路,可处理负边权(不允许负环),O(n^3)
// d[i][j] = i 到 j 的最短距离;输入 INF 表示不连通,对角线 d[i][i] = 0
void floyd(int n, vector<vector<int64_t>>& d) {
    for (int k = 0; k < n; k++)
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                if (d[i][k] < INF && d[k][j] < INF)   // 防 INF 相加溢出
                    d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}

易错点

事项 说明
溢出防护 Floyd 中 d[i][k] < INF 判断防止两个 INF 相加溢出
负环 Dijkstra 不能处理负边权;负权用 SPFA/Bellman-Ford
初始化 Floyd 不连通置 INFd[i][i] = 0

待补充

  • Bellman-Ford / SPFA(含负环检测)
  • 次短路
  • 路径记录与前驱还原