一、Bellman-Ford

Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(当然也可以是无向图)。与Dijkstra相比的优点是,也适合存在负权的图。

若存在最短路(不含负环时),可用Bellman-Ford求出,若最短路不存在时,Bellman-Ford只能用来判断是否存在负环。

松弛:  

  每次松弛操作实际上是对相邻节点的访问(相当于广度优先搜索),第n次松弛操作保证了所有深度为n的路径最短。由于图的最短路径最长不会经过超过|V| - 1条边,所以可知贝尔曼-福特算法所得为最短路径,也可只时间复杂度为O(VE)。

负边权操作

  与迪科斯彻算法不同的是,迪科斯彻算法的基本操作“拓展”是在深度上寻路,而“松弛”操作则是在广度上寻路,这就确定了贝尔曼-福特算法可以对负边进行操作而不会影响结果。

负权环判定

  因为负权环可以无限制的降低总花费,所以如果发现第n次操作仍可降低花销,就一定存在负权环。

基本操作:

  1. 创建源顶点 v 到图中所有顶点的距离的集合 distSet,为图中的所有顶点指定一个距离值,初始均为 Infinite,源顶点距离为 0;
  2. 计算最短路径,执行 V - 1 次遍历;
    • 对于图中的每条边:如果起点 u 的距离 d 加上边的权值 w 小于终点 v 的距离 d,则更新终点 v 的距离值 d;
  3. 检测图中是否有负权边形成了环,遍历图中的所有边,计算 u 至 v 的距离,如果对于 v 存在更小的距离,则说明存在环(无向图不能用这种方法判断负环)

正确性:

  Bellman-Ford 算法采用动态规划进行设计,实现的时间复杂度为 O(V*E),其中 V 为顶点数量,E 为边的数量。简单的说我们用

dis[k][v]表示经过前i个顶点到达v的最短路,易得转移方程dis[k][v] = min(dis[k][v],dis[ k -1][u] + w)。未使用滚动数组优化空间时,实现的代码如下:

 int dis[maxv][maxv];        //dis[k][v];表示选取前k个时到达i的最短距离
struct Edge
{
int u, v, w;
}edge[maxv];
int n, m; void Bellman_Ford(int s)
{
memset(dis, INF, sizeof(dis));
for (int i = ; i <= n; i++) dis[i][s] = ;
for (int k = ; k <= n - ; k++)
for (int i = ; i < m; i++)
{
int u = edge[i].u, v = edge[i].v, w = edge[i].w;
dis[k][v] = min(dis[k][v], dis[k - ][u] + w);
}
}

优化:

循环的提前退出:

  在实际操作中,贝尔曼-福特算法经常会在未达到 |V| - 1 次前就出解,|V| -1 其实是最大值。于是可以在循环中设置判定,在某次循环不再进行松弛时,直接退出循环,进行负权环判定。

队列优化:

  即SPFA

二、SPFA

是一个用于求解有向带权图单源最短路径的改良的贝尔曼-福特算法(当然也可以通过将每条边换为两条逆向的边来用于无向图)。这一算法被认为在随机的稀疏图上表现出色,并且极其适合带有负边权的图。然而SPFA在最坏情况的时间复杂度与Bellman-Ford算法相同,因此在非负边权的图中仍然最好使用Dijkstra。

原理:

  基于Bellman-Ford之外,再可以确定,松弛操作必定只会发生在最短路径前导节点松弛成功过的节点上,用一个队列记录松弛过的节点,可以避免了冗余计算。

优化:

  SPFA算法的性能很大程度上取决于用于松弛其他节点的备选节点的顺序。我们注意到其与Dijkstra很像,一方面,优先队列替换成普通的FIFO队列,而另一方面,一个节可以多次进入队列点。

  事实上,如果 q 是一个优先队列,则这个算法将极其类似于戴克斯特拉算法。然而尽管这一算法中并没有用到优先队列,仍有两种可用的技巧可以用来提升队列的质量,并且借此能够提高平均性能(但仍无法提高最坏情况下的性能)。两种技巧通过重新调整 q 中元素的顺序从而使得更靠近源点的节点能够被更早地处理。

距离小者优先(Small Lable First(SLF)):

  将总是把v压入队列尾端改为比较dis[v]与dis[q.front()]的大小(为了避免出现队列为空的操作,先将v压入队尾),并且在v较小时将v压入队列的头端。

距离大者优先(Large Lable Last(LLL)):

  我们更新队列以确保队列头端的节点的距离总小于平均,并且任何距离大于平均的节点都将被移到队列尾端。

 

改为DFS版:

  dfs版spfa判环根据:若一个节点出现2次及以上,则存在负环。具有天然的优势。由于是负环,所以无需像一般的spfa一样初始化为极大的数,只需要初始化为0就够了(可以减少大量的搜索,但要注意最开始时for一遍)。

Bellman-Ford与SPFA的更多相关文章

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

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

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

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

  3. uva 558 - Wormholes(Bellman Ford判断负环)

    题目链接:558 - Wormholes 题目大意:给出n和m,表示有n个点,然后给出m条边,然后判断给出的有向图中是否存在负环. 解题思路:利用Bellman Ford算法,若进行第n次松弛时,还能 ...

  4. 数据结构与算法--最短路径之Bellman算法、SPFA算法

    数据结构与算法--最短路径之Bellman算法.SPFA算法 除了Floyd算法,另外一个使用广泛且可以处理负权边的是Bellman-Ford算法. Bellman-Ford算法 假设某个图有V个顶点 ...

  5. Bellman—Ford算法思想

    ---恢复内容开始--- Bellman—Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题.对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数w是边集E的映射.对图G ...

  6. Bellman - Ford 算法解决最短路径问题

    Bellman - Ford 算法: 一:基本算法 对于单源最短路径问题,上一篇文章中介绍了 Dijkstra 算法,但是由于 Dijkstra 算法局限于解决非负权的最短路径问题,对于带负权的图就力 ...

  7. Dijkstra算法与Bellman - Ford算法示例(源自网上大牛的博客)【图论】

    题意:题目大意:有N个点,给出从a点到b点的距离,当然a和b是互相可以抵达的,问从1到n的最短距离 poj2387 Description Bessie is out in the field and ...

  8. POJ 2240 Arbitrage (Bellman Ford判正环)

    Arbitrage Time Limit: 1000MS   Memory Limit: 65536K Total Submissions:27167   Accepted: 11440 Descri ...

  9. poj1860 兑换货币(bellman ford判断正环)

    传送门:点击打开链接 题目大意:一个城市有n种货币,m个货币交换点,你有v的钱,每个交换点只能交换两种货币,(A换B或者B换A),每一次交换都有独特的汇率和手续费,问你存不存在一种换法使原来的钱更多. ...

  10. ACM/ICPC 之 Bellman Ford练习题(ZOJ1791(POJ1613))

    这道题稍复杂一些,需要掌握字符串输入的处理+限制了可以行走的时间. ZOJ1791(POJ1613)-Cave Raider //限制行走时间的最短路 //POJ1613-ZOJ1791 //Time ...

随机推荐

  1. 区间sum 和为k的连续区间-前缀和

    区间sum 描述 有一个长度为n的正整数序列a1--an,candy想知道任意区间[L,R]的和,你能告诉他吗? 输入 第一行一个正整数n(0<n<=1e6),第二行为长度为n的正整数序列 ...

  2. E20190407-hm

    conclude  vt. 推断; 结束,终止; 议定; vi. 终了; 作出决定或达成协议; interjection  n. 叹词,感叹词; definitely  adv. 明确地; 确切地; ...

  3. npm 的安装与使用

    创建: 2019/04/06 完成: 2019/04/07  安装 npm写在node.js里, 故安装node.js即可 https://nodejs.org/en/download/ 确认是否安装 ...

  4. jquery冲突的关键字nodeName、nodeValue和nodeType!

    原文:http://blog.csdn.net/hdfyq/article/details/52805836 [缘由]在工作流数据库设计的时候,  都节点管理的功能.  结果有2个字段为  NODE_ ...

  5. 如何在普通 UIViewController 中使用 UITableView

    本系列文章 <Swift on iOS 学习笔记> 将以不定长度.不定内容.不定形式的方式对外发布,主要记录一些 “可重用” 的知识,感谢你的阅读. 在继承自 UIViewControll ...

  6. Tyvj1474 打鼹鼠

    Description 在这个“打鼹鼠”的游戏中,鼹鼠会不时地从洞中钻出来,不过不会从洞口钻进去(鼹鼠真胆大……).洞口都在一个大小为n(n<=1024)的正方形中.这个正方形在一个平面直角坐标 ...

  7. CentOS7-MySQL8安装-使用yum库安装

    # Enable to use MySQL 5.5 [mysql55-community] name=MySQL 5.5 Community Server baseurl/$basearch/ ena ...

  8. 选择器 nth-child和 nth-of-type的区别

    <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li&g ...

  9. 捕获异常try-catch-finally

    异常分类 try-carch-finally出现规则 return关键字的使用 finally中慎用return,虽然语法上没错,但是由于finally的强制执行,影响逻辑上需要return的值 pa ...

  10. JS面向对象方法(一): 使用原生JS 实现导航栏下多级分类弹出效果

    利用二级菜单的onmouseover/out事件 重新构建一级菜单 ".hover" 样式类 代码如下: CSS部分: 在原来的目标:hover样式中 增加 .hover状态 li ...