Bellman-Ford与SPFA
一、Bellman-Ford
Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(当然也可以是无向图)。与Dijkstra相比的优点是,也适合存在负权的图。
若存在最短路(不含负环时),可用Bellman-Ford求出,若最短路不存在时,Bellman-Ford只能用来判断是否存在负环。
松弛:
每次松弛操作实际上是对相邻节点的访问(相当于广度优先搜索),第n次松弛操作保证了所有深度为n的路径最短。由于图的最短路径最长不会经过超过|V| - 1条边,所以可知贝尔曼-福特算法所得为最短路径,也可只时间复杂度为O(VE)。
负边权操作:
与迪科斯彻算法不同的是,迪科斯彻算法的基本操作“拓展”是在深度上寻路,而“松弛”操作则是在广度上寻路,这就确定了贝尔曼-福特算法可以对负边进行操作而不会影响结果。
负权环判定:
因为负权环可以无限制的降低总花费,所以如果发现第n次操作仍可降低花销,就一定存在负权环。
基本操作:
- 创建源顶点 v 到图中所有顶点的距离的集合 distSet,为图中的所有顶点指定一个距离值,初始均为 Infinite,源顶点距离为 0;
- 计算最短路径,执行 V - 1 次遍历;
- 对于图中的每条边:如果起点 u 的距离 d 加上边的权值 w 小于终点 v 的距离 d,则更新终点 v 的距离值 d;
- 检测图中是否有负权边形成了环,遍历图中的所有边,计算 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的更多相关文章
- ACM/ICPC 之 最短路径-Bellman Ford范例(POJ1556-POJ2240)
两道Bellman Ford解最短路的范例,Bellman Ford只是一种最短路的方法,两道都可以用dijkstra, SPFA做. Bellman Ford解法是将每条边遍历一次,遍历一次所有边可 ...
- poj1860 bellman—ford队列优化 Currency Exchange
Currency Exchange Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 22123 Accepted: 799 ...
- uva 558 - Wormholes(Bellman Ford判断负环)
题目链接:558 - Wormholes 题目大意:给出n和m,表示有n个点,然后给出m条边,然后判断给出的有向图中是否存在负环. 解题思路:利用Bellman Ford算法,若进行第n次松弛时,还能 ...
- 数据结构与算法--最短路径之Bellman算法、SPFA算法
数据结构与算法--最短路径之Bellman算法.SPFA算法 除了Floyd算法,另外一个使用广泛且可以处理负权边的是Bellman-Ford算法. Bellman-Ford算法 假设某个图有V个顶点 ...
- Bellman—Ford算法思想
---恢复内容开始--- Bellman—Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题.对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数w是边集E的映射.对图G ...
- Bellman - Ford 算法解决最短路径问题
Bellman - Ford 算法: 一:基本算法 对于单源最短路径问题,上一篇文章中介绍了 Dijkstra 算法,但是由于 Dijkstra 算法局限于解决非负权的最短路径问题,对于带负权的图就力 ...
- Dijkstra算法与Bellman - Ford算法示例(源自网上大牛的博客)【图论】
题意:题目大意:有N个点,给出从a点到b点的距离,当然a和b是互相可以抵达的,问从1到n的最短距离 poj2387 Description Bessie is out in the field and ...
- POJ 2240 Arbitrage (Bellman Ford判正环)
Arbitrage Time Limit: 1000MS Memory Limit: 65536K Total Submissions:27167 Accepted: 11440 Descri ...
- poj1860 兑换货币(bellman ford判断正环)
传送门:点击打开链接 题目大意:一个城市有n种货币,m个货币交换点,你有v的钱,每个交换点只能交换两种货币,(A换B或者B换A),每一次交换都有独特的汇率和手续费,问你存不存在一种换法使原来的钱更多. ...
- ACM/ICPC 之 Bellman Ford练习题(ZOJ1791(POJ1613))
这道题稍复杂一些,需要掌握字符串输入的处理+限制了可以行走的时间. ZOJ1791(POJ1613)-Cave Raider //限制行走时间的最短路 //POJ1613-ZOJ1791 //Time ...
随机推荐
- UVaLive 3695 City Game (扫描线)
题意:给定m*n的矩阵,有的是空地有的是墙,找出一个面积最大的子矩阵. 析:如果暴力,一定会超时的.我们可以使用扫描线,up[i][j] 表示从(i, j)向上可以到达的最高高度,left[i][j] ...
- UVa 1645 Count (递推,数论)
题意:给定一棵 n 个结点的有根树,使得每个深度中所有结点的子结点数相同.求多棵这样的树. 析:首先这棵树是有根的,那么肯定有一个根结点,然后剩下的再看能不能再分成深度相同的子树,也就是说是不是它的约 ...
- BlocksKit的使用
一.引言 众所周知Block已被广泛用于iOS编程.它们通常被用作可并发执行的逻辑单元的封装,或者作为事件触发的回调.Block比传统回调函数有2点优势: 允许在调用点上下文书写执行逻辑,不用分离函数 ...
- java保留小数位数
System.out.println(String.format("%.5f",new Main().minRadius(n,m)));
- HDU5920【模拟】
模拟题这种东西啊~就是自己读题,自己打,没有别的方法...贴份6000+b的code跑: #include <bits/stdc++.h> using namespace std; //t ...
- Unity(1) 编辑器结构
5个主要视图视图,未完,持续补充... 1 Project(项目) 用于显示资源 Favorites:按资源分类显示 Assets:按目录结构显示 特殊说明 Prefabs(预设),用于场景中游戏对象 ...
- 51nodcontest#24 A(xjb)
題目鏈接:http://www.51nod.com/contest/problem.html#!problemId=1804 題意:中文題誒~ 思路: 三角形個數爲n-1, a, b數組元素個數也爲n ...
- Android的文件读取与存储
Java新建文件,然后就可以写入数据了,但是Android却不一样,因为Android是 基于Linux的,我们在读写文件的时候,还需加上文件的操作模式 Environment类是一个提供访问环境变量 ...
- Java基础 使用Properties类
- ios wkwebview 跳转到新的controllerview加载页面 出现闪退问题
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { if(isF ...