简单算法-bellman最短路

一、什么是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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值