Bellman-Ford算法及其队列优化(SPFA)
一、算法概述
Bellman-Ford算法解决的是一般情况下的单源最短路径问题。所谓单源最短路径问题:给定一个图G=(V,E),我们希望找到从给定源结点s属于V到每个结点v属于V的最短路径。单源最短路径问题可以用来解决许多其他问题,其中包括下面几个最短路径的变体问题。包括单目的最短路径问题、单结点最短路径问题、所有结点对最短路径问题,这里不详细介绍。回到bellman-Ford,在这里,边的权重可以为负值。给定带权重的有向图G=(V,E)和权重函数W
: E-->R,Bellman-Ford算法返回一个布尔值,以表明是否存在一个从源点可以到达的权重为负值的环路。如果存在这样的环路,算法将告诉我们不存在解决方案。如果没有这种环路存在,算法将给出最短路径和它们的权重。边的权值可以为负数、实现简单,缺点是时间复杂度过高,高达O(VE)。但算法可以进行若干种优化,提高了效率。
自然语言描述
对有向图,用贝尔曼-福特算法求以
为源点的最短路径的过程:
- 建立
,表示目前已知源点到各个节点的最短距离,起始值
,其余皆为
。
- 建立
,
表示某节点路径上的父节点,起始值皆为NULL。
- 对
,比较
和
,并将小的赋给
,如果修改了
则
(松弛操作)
- 重复以上操作
次
- 再重复操作一次,如
,则此图存在负权环。
伪代码表示
BellmanFord(G,s)
for i = 0 to n-1 do
dist[i]= ∞
Pred[i]= 0
dist[s]=0
for k = 1 to n-1 do
foreach∈
do
ifdo
foreach∈
do
ifdo
return "No Shortest Path"
return dist[]
二、原理
为什么说最短路径不存在负环呢?
如果图G包含从s可以达到的权重为负值的环路,则最短路径权重无定义。从s到该环路上的任意结点的路径都不可能是最短路径,因为我们只要沿着任何“最短”路径再遍历一次权重为负值的环路,则总是可以找到一条权重更小的路径。如果从结点s到结点v的某条路径上存在权重为负值的环路,我们定义s到v的最短路径等于负无穷。
松弛操作
它的原理是对图进行V-1次松弛操作,得到所有可能的最短路径。对于一条边(u,v)的松弛过程为:首先测试一下是否可以对源点s到v的最短路径进行改善。测试的方法是,将从结点s到结点u之间的最短路径距离加上结点u与v之间的权重,并与当前的s到v的最短路径估计进行比较,如果前者更小,则对v.d(源点s到v的最短路径) 和v.π(前驱结点)进行更新。
每次松弛操作实际上是对相邻节点的访问,第次松弛操作保证了所有深度为n的路径最短。由于图的最短路径最长不会经过超过
条边,所以可知贝尔曼-福特算法所得为最短路径。
负边权操作
与迪科斯彻算法不同的是,迪科斯彻算法的基本操作“拓展”是在深度上寻路,用于有向无环图的最短路径算法对每条边仅松弛一次。Bellman-Ford“松弛”操作则是在广度上寻路,这就确定了贝尔曼-福特算法可以对负边进行操作而不会影响结果。
负权环判定
因为负权环可以无限制的降低总花费,所以如果发现第次操作仍可降低花销,就一定存在负权环。
三、队列优化——SPFA
求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm。松弛操作必定只会发生在最短路径前导节点松弛成功过的节点上,用一个队列记录松弛过的节点,可以避免了冗余计算。复杂度可以降低到O(kE),k是个比较小的系数(并且在绝大多数的图中,k<=2,然而在一些精心构造的图中可能会上升到很高)
参考:算法导论、http://zh.wikipedia.org/zh-cn/%E8%B4%9D%E5%B0%94%E6%9B%BC-%E7%A6%8F%E7%89%B9%E7%AE%97%E6%B3%95#.E6.9D.BE.E5.BC.9B
版权声明:本文为博主原创文章,未经博主允许不得转载。
Bellman-Ford算法及其队列优化(SPFA)的更多相关文章
- Bellman—Ford算法思想
---恢复内容开始--- Bellman—Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题.对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数w是边集E的映射.对图G ...
- Bellman - Ford 算法解决最短路径问题
Bellman - Ford 算法: 一:基本算法 对于单源最短路径问题,上一篇文章中介绍了 Dijkstra 算法,但是由于 Dijkstra 算法局限于解决非负权的最短路径问题,对于带负权的图就力 ...
- 基于bellman-ford算法使用队列优化的spfa求最短路O(m),最坏O(n*m)
acwing851-spfa求最短路 #include<iostream> #include<cstring> #include<algorithm> #inclu ...
- Dijkstra算法与Bellman - Ford算法示例(源自网上大牛的博客)【图论】
题意:题目大意:有N个点,给出从a点到b点的距离,当然a和b是互相可以抵达的,问从1到n的最短距离 poj2387 Description Bessie is out in the field and ...
- 最短路径之Bellman-Ford算法的队列优化及邻接表
参考链接:https://blog.csdn.net/qq_40626497/article/details/81139344
- poj1860 bellman—ford队列优化 Currency Exchange
Currency Exchange Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 22123 Accepted: 799 ...
- 关于SPFA的双端队列优化
7.11 Update 我做题的时候发现这样写会RE 因为在使用双端队列优化SPFA的时候 在将一个点加入队列的时候,如果队列已经空了 那么一旦出现dis[Q.front()]就会RE 可以这样修改 ...
- SPFA(Bellman-Ford队列优化)
原理:队列+松弛操作 将源点加入队尾,每一步读取队头顶点u,并将队头顶点u出队(记得消除标记):将与点u相连的所有点v进行松弛操作,如果能更新距离(即令d[v]变小),那么就更新,另外,如果点v没有在 ...
- uva 558 - Wormholes(Bellman Ford判断负环)
题目链接:558 - Wormholes 题目大意:给出n和m,表示有n个点,然后给出m条边,然后判断给出的有向图中是否存在负环. 解题思路:利用Bellman Ford算法,若进行第n次松弛时,还能 ...
随机推荐
- 九度OJ 1251:序列分割 (DFS)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:166 解决:34 题目描述: 一个整数数组,长度为n,将其分为m份,使各份的和相等,求m的最大值 比如{3,2,4,3,6} 可以分成{ ...
- Delphi 64与32位的差异
Delphi 64与32位的差异 最近,Delphi推出了64位预览版本, 我做为一个忠实的Delphier, 看到这消息后,第一时间学习,并写下这个做为以后的参考资料. 相同点: 在Delphi ...
- Cocos2d-x 3.1 环境搭建和创建project
Cocos2d-x 3.x改版了非常多,之前搭过一次环境,可是没截图.这次趁着重装电脑,一边搭建一边截图.此博文仅仅是为了记录而不是为了教学,所以很多其它讲的是搭建过程.本文基本上參考这篇博客:htt ...
- Tensorflow 初级教程(一)
初步介绍 Google 于2011年推出人工深度学习系统——DistBelief.通过DistBelief,Google能够扫描数据中心数以千计的核心,并建立更大的神经网络.Google 的这个系统将 ...
- CentOS 7 巨大变动之 systemd 取代 SysV的Init
1 systemd是什么 首先systmed是一个用户空间的程序,属于应用程序,不属于Linux内核范畴,Linux内核的主要特征在所有发行版中是统一的,厂商可以自由改变的是用户空间的应用程序. ...
- spring项目改名后不能启动的原因及解决办法
今日修改了一个spring项目的项目名称,修改后启动项目Debug as->Debug on server,过了很久也没有出现web首页,仔细看项目的定时器已经启动,eclipse的Consol ...
- dygraphs for R
dygraphs一个功能非常强大的处理时间序列的画图包!画出的图在html中打开,鼠标点处,即可得到数据信息.详情见 http://rstudio.github.io/dygraphs/index.h ...
- C#实例,熟练使用泛型数组等,课程选择小软件
CourseItem.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; ...
- LeetCode:加油站【134】
LeetCode:加油站[134] 题目描述 在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升. 你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要 ...
- python cookbook 数据结构
保留最后n个元素: from collections import deque def search (lines, pattern, history=): previous_lines = dequ ...