Bellman-Ford 算法
Bellman-Ford算法:
类似,都以松弛操作为基础,即估计的最短路径值渐渐地被更加准确的值替代,直至得到最优解。在两个算法中,计算时每个边之间的估计距离值都比真实值大,并且被新找到路径的最小长度替代。
松弛
每次松弛操作实际上是对相邻节点的访问,第 n次松弛操作保证了所有深度为n的路径最短。由于图的最短路径最长不会经过超过 |V|-1条边。
负边权操作
“松弛”操作是在广度上找路,所以对负边进行操作而不会影响结果。
负权环判定
在处理完所有的边后,如果还有边可以松弛,那么就一定存在负权环。
朴素实现
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 505;
struct Node {
int u, v, w;
} node[MAXN];
int n, m, s, t;
int dis[MAXN], pre[MAXN];
bool Bellman_Ford(int s, int t) {
memset(dis, 0x3f, sizeof(dis));
dis[s] = 0;
pre[s] = 0;
for (int i = 1; i < n; i++) {//迭代 n - 1次
for (int j = 1; j <= m; j++) {//遍历每一条边
if (dis[node[j].u] + node[j].w < dis[node[j].v]) {//松弛
dis[node[j].v] = dis[node[j].u] + node[j].w;
pre[node[j].v] = node[j].u;
}
}
}
for (int i = 1; i <= m; i++) {//判断负权环
if (dis[node[i].u] + node[i].w < dis[node[i].v]) {
return false;
}
}
return true;
}
void print(int x) {//输出路径
if (pre[x] == 0) {
printf("%d ", x);
return;
}
print(pre[x]);
printf("%d ", x);
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1, ui, vi, wi; i <= m; i++) {
scanf("%d %d %d", &ui, &vi, &wi);
node[i].u = ui;
node[i].v = vi;
node[i].w = wi;
pre[vi] = ui;
}
scanf("%d %d", &s, &t);
if (Bellman_Ford(s, t)) {
printf("%d
", dis[t]);
print(t);
} else {
printf("No Solution
");
}
return 0;
}
Spfa
思想
建一个队列 ,取队头顶点u;将与点u相连的所有点v松弛,如果能更新估计值,那么就更新,如果点v没有在队列中,那么要将点v入队,如果已经在队列中了,那么就不用,循环直到队空为止,完成了单源最短路的求解。
实现
int n, m, s, t;
int dis[MAXN];
bool vis[MAXN];
struct edge {//存边
int v, w;
edge() {}
edge(int V, int W) {
v = V;
w = W;
}
};
vector<edge> G[MAXM];
queue<int> q;
void AddEdge(int u, int v, int w) {//加边
G[u].push_back(edge(v, w));
G[v].push_back(edge(u, w));
}
void Spfa(int s, int t) {
memset(dis, 0x3f, sizeof(dis));
memset(vis, 0, sizeof(vis));
dis[s] = 0;
vis[s] = 1;
q.push(s);
while (q.size()) {
int u = q.front();//取出队头
q.pop();
vis[u] = 0;
for (int i = 0; i < G[u].size(); i++) {
if (dis[u] + G[u][i].w < dis[G[u][i].v]) {//扩展新节点
dis[G[u][i].v] = dis[u] + G[u][i].w;
if (!vis[G[u][i].v]) {
vis[G[u][i].v] = 1;
q.push(G[u][i].v);
}
}
}
}
}