最短路算法(Bellman-Ford)

之前有介绍了单元最短路算法迪杰斯特拉算法和弗洛伊德算法。但是前者没有办法处理负环。后者时间复杂度太高所以都不是最优的所以在这里介绍另一种算法。

Bellman-Ford算法:这个是利用动态规划的思想。反复理由已有的边来更新最短路。如果dist【v】满足dist【v】 <= dist【u】 + map【u】【v】。那么更新dist【v】的值。反复利用上述式子来更新dist内的值,那什么时候结束呢?最多重复n-1次,因为对于一个最短路来说,最长的边也不过是n-1条边。

实现过程:

s为源,map【】【】为地图,map【u】【v】为点u到v的边的长度,结果存在dist数组中。

1) 初始化,所有点i赋初值dist【i】 = INF 出发点为s,dist【s】 = 0;

2)对于每条边,如果dist【u】 != INF 并且 dist【v】 > dist【u】 + map【u】【v】,则赋值。

3)循环2)n-1次。或知道某次不在更新。

核心代码:

for(int i = 0 ; i < n - 1; i ++)
	for(int j = 0 ; j < m ; j++)
		if(dist[u] != INF && dist[v] > dist[u] + map[u][v]){
			dist[v] = dist[u] + map[u][v];
		}

当然了既然这个算法有处理负环的能力,那么我们可以用这个算法来判断时候有负环。

大致思路是,如果有负环那么在n次进行一遍松弛操作,dist值发生改变,就有负环。

把上述代码微调一下,如下:

for(int j = 0 ; j < m ; j++)
	if(dist[u] != INF && dist[v] > dist[u] + map[u][v]){
		return false; 
	}
return true; 


上述是邻接矩阵的写法。下面我用链式前向星的方法写一下模板(判断负环)。不懂链式前向星怎么用的小伙伴可以参考一下我之前的博客。

点击打开链接

bool bellmanFord(int s,int head[maxn],NODE edge[maxn],int dist[maxn]){
	int i,j,k;
	for(i = 0 ; i < n ; i ++) // 初始化
		dist[i] = INF;
	dist[s] = 0;
	for(int i = 0 ; i < n - 1; i ++){  //循环n-1次
		for(j = 0 ; j < n ; j ++){	//链式前向星的遍历边的方法
			if(dist[j] == INF) continue;	//若dist【j】为INF表明s没有办法直接到点j。就没有办法通过以j为起点的边来松弛其他点。
			for(k = head[j] ; k != -1 ; k = edge[k].next){
				if(edge[k].w != INF && dist[edge[k].to] > dist[j] + edge[k].w ){
					dist[edge[k].to] = dist[j] + edge[k].w;
				}
			}
		}
	}
	for(j = 0 ; j < n ; j ++){
		if(dist[j] == INF)
		continue;
		for(k = head[j];k!=-1;k = edge[k].next){
				if(edge[k].w != INF && dist[edge[k].to] > dist[j] + edge[k].w ){
				return false;
			}
		}
	}
	return true;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值