算法对所有边进行多轮松弛(relaxation),求得最短路径。
算法可以处理有负权边(无负权环)的有向图。
如果是有向图中有负权环或无向图中有负权边,则无法计算最短路径。
Relaxation means updating the shortest distance to a node if a shorter path is found through another node.
Bellman-Ford 的核心思想是动态松弛:
通过逐步松弛所有边,迭代更新从源点到其他节点的最短距离。
u → v
,检查是否可以通过 u
缩短到达 v
的路径,即:if dist[v] > dist[u] + weight(u, v)
, 则更新 dist[v] = dist[u] + weight(u, v)
。V-1
次松弛操作(V
为顶点数),确保所有可能的最短路径都被考虑到。在无负权环的图中,最短路径最多包含 V-1
条边(否则路径会重复经过节点,形成环)。
通过 V-1
次松弛,可以确保所有最短路径被正确计算。
src
的距离设为 0
,其他节点的距离设为 ∞
。u → v
,执行松弛操作。V-1
次。V
是顶点数,E
是边数。V-1
次,并额外检测负权环一次。E ≈ V²
),时间复杂度为 O(V³)
,远高于 Dijkstra 算法。V
和 E
较大时(如 V > 1000
),效率显著下降。图示:
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | /**************************************************************** * 代码作者: Alex Li * 创建时间: 2025-01-30 15:36:26 * 最后修改: 2025-01-30 16:57:58 * 文件描述: bellmanFord算法 ****************************************************************/ #include <iostream> #include <vector> #include <climits> using namespace std; // 定义边的结构体 struct Edge { int src, dest, weight; }; // Bellman-Ford算法函数 void bellmanFord(Edge edges[], int V, int E, int src) { vector<int> dist(V, INT_MAX); // 初始化距离数组,所有顶点的距离为无穷大 dist[src] = 0; // 源顶点的距离为0 bool flag = true; // 标志变量,用于检测负权重环 // 进行V-1次松弛操作 for(int i = 0; i < V; i++) { for(int j = 0; j < E; j++) { int u = edges[j].src; int v = edges[j].dest; int weight = edges[j].weight; // 如果从u到v的距离可以缩短,则更新距离 if(dist[u] != INT_MAX && dist[u] + weight < dist[v]) { // 如果在第V次松弛操作中仍然可以更新距离,说明存在负权重环 if(i == V - 1) { cout << "Graph contains negative weight cycle" << endl; flag = false; break; } dist[v] = dist[u] + weight; } } } // 如果不存在负权重环,输出各顶点的最短距离 if(flag) { cout << "Vertex Distance from Source" << endl; for(int i = 0; i < V; i++) { cout << i << "\t\t" << dist[i] << endl; } } } int main() { int V = 5; // 顶点数 int E = 8; // 边数 Edge edges[] = { {0, 1, -1}, {0, 2, 4}, {1, 2, 3}, {1, 3, 2}, {1, 4, 2}, {3, 2, 5}, {3, 1, 1}, {4, 3, -3} }; bellmanFord(edges, V, E, 0); // 调用Bellman-Ford算法 return 0; } |
负权环情况
// Edge edges[E] = { // {0, 1, 4}, // 0→1,权重4 // {0, 2, 5}, // 0→2,权重5 // {1, 2, -2}, // 1→2,权重-2 // {1, 3, 6}, // 1→3,权重6 // {2, 3, 3}, // 2→3,权重3 // {2, 4, 7}, // 2→4,权重7 // {3, 4, -1}, // 3→4,权重-1 // {4, 1, -5} // 4→1,权重-5(此边会形成负权环) // };