Bellman-Ford算法的队列优化

算法

优化核心思维:每次仅对发生变化了的点的相邻边执行松弛操作。但是如何知道当前哪些点的最短路径发生了变化呢?这里可以用一个队列来维护这些点,算法大致如下:
每次选取队首顶点u,对顶点u的所有边进行松弛操作。例如有一条u->v的边,如果通过u->v这条边使得源点到顶点v的最短路程变短(dis[u] + e[u][v] < dis[v]),且顶点v不在当前的队列中,我们就将顶点v放入队尾。需要注意的是,同一个顶点同时在队列中出现多次是毫无意义的,所以我们需要一个数组来判重(判断哪些点已经在队列中)。在对顶点u的所有出边松弛完毕后,就将顶点u出队。接下来中取出新的队首再进行如上操作,直至队列为空。
下面我们看一个具体的例子。

5 7
1 2 2
1 5 10
2 3 3
2 5 7
3 4 4 
4 5 5
5 3 6

第一行两个整数n,m。n表示顶点个数(顶点编号为1~N),m表示边的条数。接下来m行,每行有3个数x y z。表示顶点x到顶点y的边的权值为z。
在这里插入图片描述
我们用数组dis来存放1号顶点到其余各个顶点的最短路径。初始时dis[1]为0,其余为无穷大,接下来将1号顶点入队。队列这里用一个数组que以及两个分别指向队列头和尾的变量head和tail来实现。
在这里插入图片描述
先来看当前队首1号顶点的边1->2,先来看通过1->2能否让1号顶点到2号顶点的路程(即dis[2])变短,也就是说先来比较dis[2]和dis[1] + (1->2)的大小。dis[2]原来的值为inf,dis[1] + (1->2)的值为2,因此松弛成功,dis[2]的值从inf更新为2。并且当前2号顶点不再队列中,因此将2号顶点入队。
在这里插入图片描述
同样,对1号顶点剩余的出边进行如上操作,处理完毕后数组dis和队列que状态如下:
在这里插入图片描述
对1号顶点处理完毕后,就将1号顶点出队列(head++即可),再对新队首2号顶点进行如上处理。在处理2->5这条边的时候需要特别注意一下,2->5这条边虽然可以让1号顶点到5号顶点的路程变短(dis[5]的值从10更新到9),但是5号顶点已经在队列中了,因此5号顶点不能再次入队。对2号顶点处理完毕后数组dis和队列que状态如下:
在这里插入图片描述
在对2号顶点处理完毕后,需要将2号顶点出队,并依次对剩下的顶点做相同的处理,直至队列为空为止。最终数组dis和队列que的状态如下:
在这里插入图片描述

代码实现

我们还是用邻接表来储存这个图,具体代码如下:

//优化后的Bellman-Ford算法.2
#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
int main
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值