最短路径:基于C++的Bellman-Ford算法——解决负数权重路径的问题

基于C++的Bellman-Ford算法

一开始接触最短路径算法的时候,只知道Dijkstra和Floyd,后来发现有的题存在负数值的路径长度,需要用到Bellman-Ford来解,就去了解了一下这个算法。

算法思想:
Bellman-Ford算法可以解决存在负数路径长度的图,也可以检查图中是否存在负圈。在这解释一下,负圈就是某一个圈上所有路径的长度总和是负值。用双层循环,外层循环是循环每一个点,内层循环是循环每一条边,如果外层循环到了第n次还对某个边有更新就说明这里存在一个负圈使得某个点的最短路径一直在减小。

代码实现:(有详细注释)

#include

using namespace std;

const int MAX_N = 101;
const int INF = 1e9;

int N, E, s;//结点数,边数,源点
int d[MAX_N];//记录从源点出发到每个点的最短路径

struct node {
	int u, v, cost;//边的起点、终点、权重
}edge[MAX_N];

bool Bellman_Ford() {
	bool flag = false;//用于判断有没有负圈,flag为true表示有负圈
	for (int i = 0; i < N; i++) {//遍历所有的点
		for (int j = 0; j < E; j++) {//循环遍历所有的边
			int u = edge[j].u, v = edge[j].v, cost = edge[j].cost;
			if (d[v] > d[u] + cost) {//如果有一条边e(u,v)满足d[v]>d[u]+cost就更新
				d[v] = d[u] + cost;
				if (i == N - 1)//如果第N次仍然更新了最短路径,代表有负圈
					flag = true;
			}
		}
	}
	return flag;
}

void solve() {
	if (!Bellman_Ford()) {//满足这个条件表示没有负圈,就可以正确输出单源点到每个点的路径的长度
		for (int i = 0; i < N; i++) {
			cout << d[i] << endl;
		}
	}
	return;
}

int main() {
	cin >> N >> E >> s;
	for (int i = 0; i < N; i++) {
		d[i] = INF;//初始化源点到每个点的距离为无穷大
	}
	d[s] = 0;
	for (int i = 0; i < E; i++) {
		cin >> edge[i].u >> edge[i].v >> edge[i].cost;
		if (edge[i].u == s)//对于跟源点直接相连的点,设置它的最短距离为edge[i].cost
			d[edge[i].v] = edge[i].cost;
	}
	solve();
	return 0;
}

/*
4 5 0
0 2 10
1 0 0
2 1 -3
1 3 20
3 2 0
*/

你可能感兴趣的:(图,c++,算法,图论)