一、什么是bellman-ford算法?
上篇讲到了Floyd算法,它是多源最短路径算法。这里讲的bellman 则是单源最短路径算法。该算法优化了Floyd那样广撒网的形式,一定程度上减小了时间复杂度。能够计算更大图,但缺点是一次只能计算一个结点到各结点对距离。
二、算法思维
先初始化单源点到其他结点的距离为INF(无穷大),比如我们想要到达一个地方,但我们并不知道有多远,但我们知道去下个地点的距离,我们是不是可以询问下个地点的人去我们要去的地点的距离,也许他也不知道,但他也可以问他下个地点的人,我们只需要记录累加每次询问后距离,就得到了从开始点到每个地点的距离。核心代码:循环检查(单源点到一条边的起始点的距离)与(单源点到这条边结尾点的额距离 + 这条边的权值)的大小,若前者大于后者,说明单源点直接到一边的起始点的距离 比 借助中间结点的距离要大,我们就要将前者的值替换成后者的值。(d[x] = d[y] + e[i].w)。最坏每次循环只能更新一个结点的值,所以最少循环n次。
三、代码实现
用结构体存边信息。
#include <iostream>
#include <vector>
using namespace std;
const int MAX = 1005;
const int INF = 0x3fffffff;
struct Edge {
int s, e, w;
}r[1005];
int n, m, k, s, cnt;
int d[1006]; //单源点到各点的距离
void bellman() {
s = 1;
for (int i = 0; i < MAX; i++) {
d[i] = INF;
}
d[s] = 0; //s为单源点
for (int k = 1; k <= n; k++) { //n轮循环
for (int i = 1; i < cnt; i++) { //检查每条边
int x = r[i].s; int y = r[i].e;
if (d[x] > d[y] + r[i].w)
d[x] = d[y] + r[i].w;
}
}
}
int main() {
int a, b, c;
while (cin >> n >> m) {
cnt = 0;
for (int i = 1; i <= m; i++) {
cin >> a >> b >> c;
r[cnt].s = a; r[cnt].e = b; r[cnt++].w = c;
r[cnt].s = b; r[cnt].e = a; r[cnt++].w = c;
}
bellman();
for (int i = 1; i <= n; i++)
cout << d[i] << " ";
cout << endl;
}
system("pause");
return 0;
}
四、输出最短路径
通过借助中间结点得到最短路径,可以借助数组记录单源点到该结点的最后一个结点,例如:(1,4)是通过(1,3) + (3,4),我们可以知道(1,4)的最后一次经过的结点是3,所以pre[4]=3;同理,(1,3)是通过(1,2) + (2,3),我们可以知道(1,3)的最后一次经过的结点是2。
五、代码实现
#include <iostream>
#include <vector>
using namespace std;
const int MAX = 1005;
const int INF = 0x3fffffff;
struct Edge {
int s, e, w;
}r[1005];
int n, m, k, s, cnt;
int d[1006]; //单源点到各点的距离
int pre[1005];
void bellman() {
s = 1;
for (int i = 0; i < MAX; i++) {
d[i] = INF;
}
d[s] = 0; //s为单源点
for (int k = 1; k <= n; k++) { //n轮循环
for (int i = 1; i < cnt; i++) { //检查每条边
int x = r[i].s; int y = r[i].e;
if (d[x] > d[y] + r[i].w) {
d[x] = d[y] + r[i].w;
pre[x] = y; //记录路径
}
}
}
}
void print(int e,int t) { //输出路径
if(pre[e] != s) print(pre[e],t);
cout << pre[e] << "-->";
if (e == t) cout << e << endl;
}
int main() {
int a, b, c;
while (cin >> n >> m) {
cnt = 0;
for (int i = 1; i <= m; i++) {
cin >> a >> b >> c;
r[cnt].s = a; r[cnt].e = b; r[cnt++].w = c;
r[cnt].s = b; r[cnt].e = a; r[cnt++].w = c;
}
bellman();
for (int i = 1; i <= n; i++)
cout << d[i] << " ";
cout << endl;
cin >> a;
print(a, a);
}
system("pause");
return 0;
}