最短路总结

分层图

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

算法 核心思想 适用 时间复杂度 能否处理负权边 能否处理负环
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];
        }
    }
}
相关推荐
2601_967760788 小时前
2026年PDF压缩与页码添加工具技术实测:性能、算法与本地化适配深度对比
算法·pdf
不会就选b9 小时前
算法日常・每日刷题--<贪心>7
数据结构·算法·leetcode
moonrailgun9 小时前
用 Node.js 复刻 Codex Astra 的终端星光
前端·javascript·算法
罗西的思考10 小时前
[Agent Memory / 强化学习] MemPO源码学习笔记 ---(1)--- 总体
人工智能·算法·机器学习
lvwangshu11 小时前
图论:LCA、树的直径、树的重心、二分图与 Tarjan 缩点
算法·图论
爱吃苹果的日记本11 小时前
数据结构第一课
c语言·数据结构·数据库·学习·c#
张小姐的猫11 小时前
【AI大模型接入SDK】 —— Gemini接入封装
android·数据结构·数据库·c++·人工智能·python
302wanger11 小时前
干与湿:AI 拿走脑力之后,人剩下什么
算法
计算机编程-吉哥12 小时前
脑肿瘤MRI智能识别系统:基于深度学习的像素级脑肿瘤语义分割平台【计算机毕业设计选题推荐】
人工智能·python·深度学习·算法·毕业设计·课程设计·大数据毕业设计选题推荐
用户2049375549513 小时前
端侧语音部署踩坑:模型能跑不等于终端真的能用
后端·算法