最短路(Bellman_Ford)

本文介绍了贝尔曼-福特算法,用于解决包含负权重边的图中最短路径问题。与Dijkstra算法不同,贝尔曼-福特算法允许处理负权重,通过迭代所有边来更新距离,最多进行n-1次循环。当无更新发生时,算法终止。文章提供了一个C++实现的示例代码,并展示了如何寻找从特定起点到所有顶点的最短路径。
摘要由CSDN通过智能技术生成

Graph 图论

最短路(Bellman_Ford)

缺点:不能计算包含负环的图
在这里插入图片描述

前面我们已经学习了dijkstra算法来求最短路,但是dijkstra有一个很大的问题就是无法计算有负权值的图,这是因为dijkstra找到一个当前dist最小点的时候便将该点设置为已访问,便不再处理该点,这对边权为非负数的时候适用,因为该点的权值不会再被更新(dijkstra),然而如果一个图的边带有负权值,那么该算法便不再适用,因为即使是当前dist最小的点之后还有可能会被负值所更新,所以我们就不能像dijkstra那样将一个标记为已被访问就不在管他,我们不能对点进行处理了,所以我们换个方式而是对边进行处理,每一条边都对应了三个属性,一个是起点,一个是终点,一个是边权,所以我们很容易想到用一个结构体来存储这三种属性:

struct edge{
	int a,b;
	int cost;
};
edge map[600001];

然后我们就是对边进行处理了,一共我们有m条边,我们每次循环就要对这m条边进行遍历,确保我们每次更新dist值都能够考虑所有的边对其的影响,这样的循环最多进行 n-1 次(如果不存在从起点可达的负环,那么最短路不会经过同一个点两次,也就是说最多通过v-1条边,while循环醉倒执行n-1次),我们可以设置一个update来判断是否当前循环是否有更新dist值,如果进行中某次循环没有更新dist值,也就是说经过这次循环程序中的任何值都没有发生变化,所以就可以退出来了,就没有必要再做剩下的循环了(因为循环下去我们所需要的dist的值也不会再发生变化了)。
循环的主要内容是我们判断一下当前我们所知的这条边是否能对dist值进行更新,这个想法跟dijkstra一样,

if(dist[E.b] > dist[E.a] + E.cost)
=> dist[E.b] = dist[E.a] + E.cost;
完整代码如下:

#include<iostream>
#include<cstring>
using namespace std;
const long long inf = 0x7f7f7f7f;
struct edge{
	int a,b;
	int cost;
};
edge map[600001];
int n,m;
int dist[100001];
void bellman_ford(int begin){
	memset(dist,inf,sizeof(dist));
	dist[begin] = 0;
	bool update = true;
	while(update){
		update = false;
		for(int i=0;i<m;i++){
			edge E = map[i];
			if(dist[E.b] > dist[E.a] + E.cost){
				update = true;
				dist[E.b] = dist[E.a] + E.cost;
			}
		}
	}
}
int main(){
	int begin;
	cin >> n >> m;
	cin >> begin;
	for(int i=0;i<m;i++){
		cin >> map[i].a >> map[i].b >> map[i].cost;
	}
	bellman_ford(begin);
	for(int i=1;i<=n;i++){
		if(dist[i]==inf) cout << 2147483647 << " ";
		else cout << dist[i] << " ";
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值