最短路径--Bellman-Ford的队列优化

简单介绍

  • 上一篇提到了Bellman-Ford算法的另一种优化:每次仅对最短路程发生变化了的点的相邻边执行松弛操作
  • 这一篇将用队列存储点,大致算法如下

讲解

  • 用一个例子来详细说明
    在这里插入图片描述
  • 1号顶点为源点,用dis数组存储1号顶点到其余各个顶点的最短路径,初始时dis[1]=0,其余为∞,队列用一个数组que和head、tail指向队首和队尾
  1. 初始时将源点加入队列,每次从队首取出一个顶点,并对与其相邻的所有顶点进行松弛尝试,若某个相邻的顶点松弛成功且这个相邻的顶点不在队列中,则将它加到队列中,对当前顶点处理完毕后立即出队,并对下一个新队首进行如上操作直到队列为空,算法结束

  2. 可以用一个book数组来标记每个顶点是否处在队列中,但是注意这里的一个顶点很可能在出队列之后再次被放到队列中

  3. 也就是当一个顶点的最短路径估计值变小后,需要对其所有出边进行松弛,但是如果这个顶点的最短路程估计值再次变小,仍需要对其所有的出边再次进行松弛,这样才能保证相邻顶点的最短路程估计值同步更新

  4. 用队列优化的算法在于,可以降低其时间复杂度

  5. 松弛的顺序是按队列中的顺序来松弛的

  • 下面来展示具体的松弛步骤
    在这里插入图片描述

完整代码

#include<stdio.h>
#define MAX 999999 
int main(){
	int n,m,i,j,k,a;
	//u,v,w数组的大小根据实际情况来设,要比m的最大值大1 
	int u[8],v[8],w[8];
	//first,next数组的大小根据实际情况来设,first比n的最大值大1,next比m的最大值大1  
	int first[6],next[8];
	//book数组用记录哪些点已经在队列中 
	int dis[6],book[6];
	int que[101]={0},head=1,tail=1;
	scanf("%d %d %d",&n,&m,&a);
	//初始化dis数组
	for(i=1;i<=n;i++)
		dis[i]=MAX;
	dis[a]=0;
	//初始化book数组
	for(i=1;i<=n;i++)
		book[i]=0;
	//初始化first数组为-1,表示暂时没有边
	for(i=1;i<=n;i++)
		first[i]=-1;
	 for(i=1;i<=m;i++){
		scanf("%d %d %d",&u[i],&v[i],&w[i]);
		next[i]=first[u[i]];
		first[u[i]]=i;
	}
	//源点入队
	que[tail]=a;
	tail++;
	book[a]=1;//标记源点已入队
	while(head<tail){
		k=first[que[head]];
		while(k!=-1){
			if(dis[v[k]]>dis[u[k]]+w[k]){
				dis[v[k]]=dis[u[k]]+w[k];
				if(book[v[k]]==0){
					que[tail]=v[k];
					tail++;
					book[v[k]]=1;
				}
			}
			k=next[k];
		}
		book[que[head]]=0;
		head++;
	} 
	for(i=1;i<=n;i++)
		printf("%d ",dis[i]);
	return 0;
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值