最短路总结

分层图

将原问题中的额外状态(如剩余步数、资源数量、模数等)作为 " 层 " 来扩展图,从而将复杂约束转化为普通的最短路问题。

算法 核心思想 适用 时间复杂度 能否处理负权边 能否处理负环
Dijkstra 贪心:从起点开始,每次从未钉死最短路的点中选取距离最近的点,并用它去"松弛"其邻接点 单源最短路,非负权图 O(m log n) 不能 不能
Bellman-Ford 暴力枚举边 :对所有边进行 n-1 次松弛操作,每次尝试更新所有边终点的距离 单源最短路,存在负权边的有向图 O(nm)
SPFA 队列优化 BF:是 Bellman-Ford 算法的队列优化版,只对"被成功松弛"的点的出边进行松弛,避免了无效的边遍历 单源最短路,存在负权边的有向图 平均 O (km),最坏 O (nm)
Floyd 区间 DP :通过枚举中间点 k 来松弛任意两点 ij 之间的距离 多源最短路,稠密图 O(n³) 有向图可以处理
Johnson 贪心:通过一次 SPFA 来判断负环,然后跑 n 遍 Dijkstra 多源最短路,稀疏图 O(n² log n + nm)

最短路模版

复制代码
//Dijkstra
const int maxn = 100010;
struct node {
    int dis, pos;
    bool operator<(const node &x) const { return x.dis < dis; }
};
int n, m, s, t;
int dis[maxn];
bool vis[maxn];
vector<pair<int, int>> g[maxn];
priority_queue<node> q;
void dijkstra() {
    for (int i = 1; i <= n; i++) {
        dis[i] = 0x3f3f3f3f;
        vis[i] = 0;
    }
    dis[s] = 0;
    q.push({ 0, s });
    while (!q.empty()) {
        node tmp = q.top();
        q.pop();
        int x = tmp.pos;
        if (vis[x]) {
            continue;
        }
        vis[x] = 1;
        for (auto [y, w] : g[x]) {
            if (dis[y] > dis[x] + w) {
                dis[y] = dis[x] + w;
                if (!vis[y]) {
                    q.push({ dis[y], y });
                }
            }
        }
    }
}
复制代码
//SPFA
const int maxn = 1e4 + 5;
const int inf = 1e9;
int n, m, s, u, v, w, t;
int dis[maxn];
bool vis[maxn];
vector<pair<int, int>> g[maxn];
void spfa() {
    for (int i = 1; i <= n; i++) {
        dis[i] = inf;
    }
    queue<int> q;
    q.push(s);
    vis[s] = 1;
    dis[s] = 0;
    while (!q.empty()) {
        int t = q.front();
        q.pop();
        vis[t] = 0;
        for (int i = 0; i < g[t].size(); i++) {
            int to = g[t][i].first;
            int w = g[t][i].second;
            if (dis[to] > dis[t] + w) {
                dis[to] = dis[t] + w;
                if (vis[to]) {
                    continue;
                }
                vis[to] = 1;
                q.push(to);
            }
        }
    }
}
复制代码
//Floyd
for (int k = 1; k <= n; k++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
            }
        }
    }
复制代码
//Johnson
const int maxn = 3e3 + 5;
const int INF = 1e9;
struct node {
    int dis;
    int pos;
    bool operator<(const node& oth) const { return dis > oth.dis; }
};
int n, m;
vector<pair<int, int> > g[maxn];
vector<pair<int, int> > g2[maxn];
int dis[maxn];
int cnt[maxn];
bool inq[maxn];
int h[maxn];
int ans[maxn][maxn];
bool SPFA(int s) {
    queue<int> q;
    for (int i = 0; i <= n; i++) {
        dis[i] = INF;
        cnt[i] = 0;
        inq[i] = 0;
    }
    dis[s] = 0;
    inq[s] = 1;
    q.push(s);
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        inq[u] = 0;
        for (auto v : g[u]) {
            int nod = v.first;
            int w = v.second;
            if (dis[u] + w < dis[nod]) {
                dis[nod] = dis[u] + w;
                if (!inq[nod]) {
                    q.push(nod);
                    inq[nod] = 1;
                    cnt[nod]++;
                    if (cnt[nod] > n) {
                        return 0;
                    }
                }
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        h[i] = dis[i];
    }
    return 1;
}
void dijkstra(int s) {
    priority_queue<node> q;
    for (int i = 1; i <= n; i++) dis[i] = INF;
    memset(inq, 0, sizeof(inq));
    dis[s] = 0;
    q.push({ 0, s });
    while (!q.empty()) {
        int u = q.top().pos;
        q.pop();
        if (inq[u])
            continue;
        inq[u] = 1;
        for (auto v : g2[u]) {
            int nod = v.first;
            int w = v.second;
            if (dis[nod] > dis[u] + w) {
                dis[nod] = dis[u] + w;
                if (!inq[nod]) {
                    q.push({ dis[nod], nod });
                }
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        if (dis[i] >= INF) {
            ans[s][i] = INF;
        } else {
            ans[s][i] = dis[i] - h[s] + h[i];
        }
    }
}
相关推荐
致Great2 小时前
OpenAI 又把 Codex 往前推了一步: 以后做 Agent,没必要都造一个聊天框
算法
aqiu1111113 小时前
【算法刷题】蓝桥杯/AtCoder:删除元素后的中位数问题(Symmetry / Median)
算法·蓝桥杯·排序·中位数
看我眼色行事^ \/ ^4 小时前
2024.05.11 360春招WEB前端编程题
算法
来一碗刘肉面4 小时前
有向无环图 DAG(描述表达式)
数据结构
一只肥瘫瘫4 小时前
编码器 PLL 角度与速度观测器原理
人工智能·算法
Nil2084 小时前
leetcode 146LRU缓存
算法·leetcode·缓存
郝学胜_神的一滴5 小时前
干货版《算法导论》18:遍历增删原理、时间复杂度与集合序列实现全解
数据结构·算法
-dzk-5 小时前
【滑动窗口】LC 3.无重复字符的最长子串
算法·滑动窗口
BK贝壳5 小时前
Python底层:1亿个布尔值缓存失效标记,list爆内存numpy爆拷贝,bool-hybrid-array混合存储实测
数据结构·python·缓存·性能优化·list·numpy