最短路(贝尔曼·福德)
2026-07-14 16:09:46
发布于:广东
(防透视)——————————————————————————————————————————————
上课老师也是讲了最短路语法,给大家简单分享一些。老师大号
Bellman-Ford模板:
1.1 为何需要n-1轮松弛?
- 理论依据:无负环图中,任意两点最短路径最多包含n-1条边(n为节点数)。
- 松弛过程:
- 第1轮:得到最多1条边的最短路径;
- 第k轮:得到最多k条边的最短路径;
- 第n-1轮后:所有最短路径必然收敛。
- 提前终止优化:若某轮无任何松弛发生,可提前结束循环。
1.2 负环检测机制
- 关键判定:若第n轮松弛仍能更新距离,则图中存在从源点可达的负权环。
- 原理:负环允许无限绕行使路径长度无限减小,最短路径无定义。
基础code:
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
struct Edge { int u, v, w; };
const int INF = 0x3f3f3f3f;
vector<Edge> edges; // 边集(无需建图)
int dist; // 源点到各点距离
int n, m; // 节点数、边数
// 返回值:true=存在负环,false=无负环
bool bellman_ford(int start) {
// 初始化:源点距离为0,其余为无穷大
fill(dist, dist + n + 1, INF);
dist[start] = 0;
// **核心:执行n-1轮松弛**
bool updated = false;
for (int i = 1; i <= n - 1; i++) {
updated = false;
for (auto &e : edges) {
// 仅当起点可达时才松弛
if (dist[e.u] != INF && dist[e.u] + e.w < dist[e.v]) {
dist[e.v] = dist[e.u] + e.w;
updated = true;
}
}
// 提前终止:无更新即收敛
if (!updated) break;
}
// **第n轮检测负环**
if (updated) {
for (auto &e : edges) {
if (dist[e.u] != INF && dist[e.u] + e.w < dist[e.v]) {
return true; // 存在负环
}
}
}
return false; // 无负环
}
2.2 关键实现细节
- 边集存储:直接使用边列表(无需邻接表),实现更简单。
- INF安全处理:松弛时必须检查
dist[u] != INF,避免溢出导致错误更新。 - 负环判定位置:
- 若仅需最短路(不关心负环),可省略第n轮检测;
- 若需严格判断最短路存在性,必须执行第n轮验证。
3. 负环检测的两种场景
3.1 源点可达负环
- 现象:源点到负环上任意节点的距离会无限减小。
- 处理:算法直接返回负环存在,此时最短路径无定义。
3.2 源点不可达负环
- 现象:负环存在但源点无法到达,不影响其他节点的最短路。
- 处理:Bellman-Ford仍能正确计算非负环连通分量内的最短路径。
4. 适用场景与限制
4.1 何时使用Bellman-Ford?
- 必须检测负环:如差分约束系统、金融套利检测等场景。
- 图规模极小:节点数 且边数 (否则SPFA更优)。
- 教学演示:理解松弛操作和负环原理的基础工具。
4.2 关键限制
- 效率低下:最坏时间复杂度 ,大规模图中性能远差于SPFA。
- 无法计算负环路径:仅能判定存在性,不能输出负环具体路径。
- 非负权图禁用:此时应优先选择 Dijkstra(非负权)或SPFA(含负权)。
5. 与其他算法对比
| 算法 | 负权边支持 | 负环检测 | 时间复杂度 | 适用场景 |
|---|---|---|---|---|
| Bellman-Ford | 支持 | 支持 | 小规模图+必须检测负环 |
| SPFA | 支持 | 支持 | 平均 | 带负权边的单源最短路(竞赛首选) |
| Dijkstra | 不支持 | 不支持 | | 非负权图(实际工程首选) |
| Floyd | 支持 | 支持 | | 小规模图的全源最短路 |
蒟蒻太菜了,只会写这一些
这里空空如也



















有帮助,赞一个