算法特性
-
它的原理是对图进行最多 次松弛操作, 得到所有可能的最短路径。其优于迪科斯彻算法的方面是边的权值可以为负数、实现简单,缺点是时间复杂度过高, 高达。但算法可以进行若干种优化,提高了效率。
-
Bellman Ford 算法每次对所有的边进行松弛, 每次松弛都会得到一条最短路径, 所以总共需要要做的松弛操作是 次。 在完成这么多次松弛后如果还是可以松弛的话,那么就意味着,其中包含负环。
-
相比狄克斯特拉算法(Dijkstra algorithm), 其最大优点便是 Bellman–Ford 支持存在负权重的情况, 并且代码实现相对简单。缺点便是时间复杂度较高,达到 , 代表顶点数, 代表边数。
算法流程
这个算法非常暴力,感觉甚至有点 floyd 算法的感觉,就是进行 n - 1 次尝试(点的个数是 n), 然后在每次尝试中, 我们让每个点都试试看,假如在当前的路径上加入一个中间点,会不会让路径更短, 在最差情况下,如果一个图里面所有点在一条直链上, 最多可能途径 n - 1 个点(不包括起点)。这就是为什么要尝试 n - 1 次。
模板题目
题目传送门: https://www.luogu.com.cn/problem/P3371
算法代码
#include <iostream>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
const int N = 1e4 + 5;
struct Target {
int target_node;
long long cost;
};
vector<Target> adj[N];
void add(int a, int b, long long cost) { adj[a].push_back({b, cost}); }
struct Edge {
int a;
int b;
long long cost;
};
vector<Edge> edges;
long long dis[N];
int main() {
int n, m, s;
cin >> n >> m >> s;
for (int i = 1; i <= n; i++) {
dis[i] = 0x7fffffff;
}
dis[s] = 0;
int a, b, c;
for (auto i = 0; i < m; i++) {
cin >> a >> b >> c;
add(a, b, c);
edges.push_back({a, b, c});
}
for (int i = 1; i <= n; i++) {
for (auto &edge : edges) {
if (dis[edge.b] > dis[edge.a] + edge.cost) {
dis[edge.b] = dis[edge.a] + edge.cost;
}
}
}
for (auto i = 1; i <= n; i++) {
cout << dis[i] << " ";
}
cout << endl;
return 0;
}