Bellman-Ford算法在每实施依次松弛后,就会有一些顶点已经求得最短路,此后这些顶点的最短路的估计值就会一直不变,不再收后续松弛操作的影响,但是每次还要判断是否需要松弛,这就浪费时间了。

从上面可以得到启发:每次仅对最短路估计值发生变化了的顶点的所有出边执行松弛操作。

but,如何知道当前哪些点的最短路程发生了变化呢?

这里可以用一个队列来维护这些点,算法大致如下:

  每次选取队首顶点u,对顶点u的所有出边进行松弛操作。例如有一条u->v的边,如果通过u->v这条边使得源点到顶点v的最短路程变短

(dis[u]+e[u][v]<dis[v]),且顶点v不在当前的队列中,就将顶点v放入队尾。

  需要注意的是,同一个顶点同时在队列中出现多次是没有意义的,所以需要一个数组来判重(判断哪些点已经在队列中)。

  在对顶点u的所有出边松弛完毕后,就将顶点u出队。

  接下来不断从队列中取出新的队首顶点再进行如上操作,直到队列空为止。

对于上图,采用队列优化的方法求得最短路径。

下面是代码实现,用邻接矩阵来存储这个图,具体如下:

#include <stdio.h>

#define INF 999999
int book[]; //初始化为顶点都不在队列
int que[]; // 松弛成功并且顶点不在队列则并入队列 int main(int argc, char const *argv[])
{
int i, j, n, m;
int q1, q2, q3;
int dis[], e[][];
int head, tail;
//读入n和m,n表示顶点个数,m表示边的个数
scanf_s("%d %d", &n, &m);
//初始化邻接矩阵
for (i = ; i <= n; ++i)
{
for (j = ; j <= n; ++j)
{
if (i == j)
{
e[i][j] = ;
}
else
{
e[i][j] = INF;
}
}
}
//输入边
for (i = ; i <= m; ++i)
{
scanf_s("%d %d %d", &q1, &q2, &q3);
e[q1][q2] = q3;
} //初始化dis数组
for (i = ; i <= n; ++i)
{
dis[i] = INF;
}
dis[] = ; //初始化dis[1]为0,其他为∞ head = tail = ;
que[tail] = ; //1号顶点入队
tail++;
book[] = ; //标记1号顶点已经入队
while (head < tail) //队列不为空的时候循环
{
for (i = ; i <= n; ++i)
{
if (e[que[head]][i] != INF && dis[i] > dis[que[head]] + e[que[head]][i])
{
dis[i] = dis[que[head]] + e[que[head]][i];
if (!book[i]) //顶点不在队列,加入队列
{
book[i] = ;
que[tail++] = i;
}
}
}
//出队
book[que[head]] = ; //重新标记不在队列
head++; //相当于出队
} printf("最终结果为:\n");
for (i = ; i <= n; ++i)
{
printf(" 1号顶点到%d号顶点的最短距离为:%d\n", i, dis[i]);
}
printf("\n");
getchar();
getchar();
return ;
}

  下面总结一下。初始时将源点加入队列。每次从队首(head)取出一个顶点,并对与其相邻的所有顶点进行松弛尝试,若某个相邻的顶点松弛成功,且这个相邻的顶点不在队列中(不在head和tail之间),则将它加入到队列中。对当前顶点处理完毕后立即出队,并对下一个新队首进行如上操作,直到队列为空算法结束。

  使用队列优化的Bellman-Ford算法在形式上与广度优先搜索非常类似,不同的是在广度优先搜索的时候一个顶点出队后通常就不会再重新进入队列。而队列优化的Bellman-Ford算法一个顶点很可能在出队列之后再次被放入队列,也就是当一个顶点的最短路程估计值变小后,仍需要对其所有出边再次进行松弛,这样才能保证相邻顶点的最短路程估计值同步更新。

  如何判断通过队列优化的Bellman-Ford算法一个图有负环呢?

  如果某个点进入队列的次数超过n次,那么这个图肯定存在负环。

  使用队列优化的Bellman-Ford算法的关键之处在于:只有那些在前一遍松弛中改变了最短路程估计值的点,才可能引起它们邻接点最短路程估计值发生改变。

Bellman-Ford的队列优化的更多相关文章

  1. poj1860 bellman—ford队列优化 Currency Exchange

    Currency Exchange Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 22123   Accepted: 799 ...

  2. 关于SPFA的双端队列优化

    7.11 Update 我做题的时候发现这样写会RE 因为在使用双端队列优化SPFA的时候 在将一个点加入队列的时候,如果队列已经空了 那么一旦出现dis[Q.front()]就会RE 可以这样修改 ...

  3. 最小生成树 prime + 队列优化

    存图方式 最小生成树prime+队列优化 优化后时间复杂度是O(m*lgm) m为边数 优化后简直神速,应该说对于绝大多数的题目来说都够用了 具体有多快呢 请参照这篇博客:堆排序 Heapsort / ...

  4. BestCoder Round #89 02单调队列优化dp

    1.BestCoder Round #89 2.总结:4个题,只能做A.B,全都靠hack上分.. 01  HDU 5944   水 1.题意:一个字符串,求有多少组字符y,r,x的下标能组成等比数列 ...

  5. 单调队列优化DP,多重背包

    单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...

  6. ACM/ICPC 之 最短路径-Bellman Ford范例(POJ1556-POJ2240)

    两道Bellman Ford解最短路的范例,Bellman Ford只是一种最短路的方法,两道都可以用dijkstra, SPFA做. Bellman Ford解法是将每条边遍历一次,遍历一次所有边可 ...

  7. bzoj1855: [Scoi2010]股票交易--单调队列优化DP

    单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w ...

  8. [poj3017] Cut the Sequence (DP + 单调队列优化 + 平衡树优化)

    DP + 单调队列优化 + 平衡树 好题 Description Given an integer sequence { an } of length N, you are to cut the se ...

  9. UESTC 880 生日礼物 --单调队列优化DP

    定义dp[i][j]表示第i天手中有j股股票时,获得的最多钱数. 转移方程有: 1.当天不买也不卖: dp[i][j]=dp[i-1][j]; 2.当天买了j-k股: dp[i][j]=max(dp[ ...

  10. 双参数Bellman-ford带队列优化类似于背包问题的递推

    为方便起见,将Bellman-ford队列优化称为SPFA,= = 抓住 ZMF (ZMF.pas/c/cpp) 题目描述 话说这又是一个伸手不见五指的夜晚,为了机房的电子竞技事业永远孜孜不倦的 ZM ...

随机推荐

  1. bzoj2946

    题解: 和poj1226差不多 把翻转去掉 然后不要忘记开大数组和二分的上限答案 代码: #include<bits/stdc++.h> using namespace std; type ...

  2. 手动配置 Windows 时间服务

    手动配置 Windows 时间服务 要将内部时间服务器配置为与外部时间源同步,请按照下列步骤操作: 将服务器类型更改为 NTP. 为此,请按照下列步骤操作: 选择 “开始” . “运行”,键入 reg ...

  3. git-github-TortoiseGit综合使用教程(一)简介

    简介: 本系列教程将参考廖雪峰的git系列教程,使用github的web界面,和TortoiseGit图形界面windows程序来实现. git 是什么: Git是目前世界上最先进的分布式版本控制系统 ...

  4. 多态概念,C++

    body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...

  5. debian服务器解决中文安装后出现乱码的问题

    由于安装debian选择语言时选择了简体中文安装,但内核没有中文字库,导致某些字符显示为乱码(菱形,方块). 解决办法: 普通用户如果没有设置sudo权限,首先切换到root权限.然后: apt-ge ...

  6. jackson中的@JsonBackReference

    #    StackOverflowError / 无限递归 / json递归 / JsonBackReference 环境:springmvc+hibernate+json 在controller返 ...

  7. BBbacktrace installation

    1: get the installation package https://backtrackbb.readthedocs.io/en/latest/Method.html#overview ht ...

  8. Install SharePoint 2013 with SP1 on Windows Server 2012 R2 error - This Product requires .NF 4.5

    博客地址:http://blog.csdn.net/FoxDave 最近因为项目需要要搭建SharePoint 2013的开发环境. 准备了Windows Server 2012 R2系统和Sha ...

  9. tf 模型保存

    tf用 tf.train.Saver类来实现神经网络模型的保存和读取.无论保存还是读取,都首先要创建saver对象. 用saver对象的save方法保存模型 保存的是所有变量 save( sess, ...

  10. 虚拟机提示:无法打开内核设备“\\.\Global\vmx86”: 系统找不到指定的文件

    虚拟机提示:无法打开内核设备“\\.\Global\vmx86”: 系统找不到指定的文件 Win 10 vmware12 无法打开内核设备“\\.\Global\vmx86”: 系统找不到指定的文件. ...