队列优化——Bellman-Ford算法

Bellman-Ford算法如果存在一个顶点已经达到最短路径但还会继续判断是否需要松弛

优化关键:每次仅对最短路径估计值发生变化了的顶点的所有出边执行松弛操作

队列优化的Bellman-Ford算法

原理:我们可以用一个队列来维护,该顶点最短路径估计值发生变化的点,因为如果该顶点最短路径发送了变化,则对后续经过该顶点的最短路径也会发生变化,则需要再次以该顶点进行松弛

算法关键

使用邻接表来存储边和点(稀疏图)

先将源点入队,然后以该源点为队首进行相邻边的松弛,如果该队首顶点的出边成功松弛,则出边对应的顶点入队

同时,入队的点必须不重复,因为重复则会进行无意义的松弛,松弛不会成功

该队首所有邻边松弛完毕后,出队,队列中下一个顶点为队首进行松弛,以此类推

代码

#include <iostream>
using namespace std;

int main()
{
	int n,m;
	cin>>n>>m;
	//存储边的信息 
	int u[m+1],v[m+1],w[m+1];
	//存储点和其所有相邻边
	int first[n+1],next[m+1];
	int dis[n+1]={0},book[n+1]={0};//book数组记录哪些顶点已经在队列中
	int que[101]={0},head = 1,tail = 1;//定义队列,并初始化
	int inf = 99999999;
	//初始化dis数组,以1作为源点为例 
	for(int i=1;i<=n;i++){
		dis[i] = inf;
	} 
	dis[1] = 0;
	
	//初始化first数组,即邻接表存储所有顶点的相邻边
	for(int i=1;i<=n;i++){
		first[i] = -1;
	}
	//建立邻接表 
	for(int i=1;i<=m;i++){
		cin>>u[i]>>v[i]>>w[i];
		//建立邻接表的核心算法 
		next[i] = first[u[i]];
		first[u[i]] = i;
	}
	
	//1号顶点入队 
	que[tail] = 1;
	tail ++;
	book[1] = 1;//标记1号顶点已经在队列中
	
	while(head < tail){//队列不为空循环 
		int k = first[que[head]];//取出需要处理的顶点
		while(k != -1){
			if(dis[v[k]] > dis[u[k]] + w[k]){
				dis[v[k]] = dis[u[k]] + w[k];//更新顶点1到v[k]的最短路径
				//判断该顶点是否在队列中 
				if(book[v[k]] == 0){
					//入队 
					que[tail] = v[k];
					tail ++;
					book[v[k]] = 1;
				} 
			}
			k = next[k];
		}
		//出队 
		book[que[head]] = 0;
		head ++;
	}
	
	//输出1到其余顶点的最短路径
	for(int i=1;i<=n;i++){
		cout<<dis[i]<<" ";
	} 
	return 0;
}

通过队列优化的Bellman-Ford算法判断图是否有负权环:如果某个点进入队列的次数超过n此,那么一定存在负权环

复杂度分析:

时间复杂度:最坏情况下也是O(NM)

空间复杂度:O(M)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值