算法之SPFA的前置:Bellman-Ford算法
SPFA
我们都知道一个叫SPFA的算法,它是用来计算单源最短路径的,但是,众所周知它不是很稳定,容易退化。
SPFA是基于什么被提出的?
基于一个叫做Bellman-Ford的算法。
Bellman-Ford
bellman算法实际上比dijkstra有更高的普适性,因为它可以处理有负边权图。但无法处理存在负权回路情况。
算法的时间复杂度为\(O(VE)\),V是顶点数,E是边数。
以下是bellman-ford的伪代码:
#define MAXN 最大点数
#define MAXM 最大边数
int dis[MAXN],w[MAXM],s;//dis 表示从出发点s到i点的当前最短路径长度,w表示边权值,s表示出发点。
struct lines{//边集结构体
int u,v;//出发点,到达点
}l[MAXM];
/*
初始化,将dis[s]设为0,dis[其他]设为0x3f3f3f3f,输入边集。
*/
for(int i=1;i<=MAXN;i++){
for(int j=1;j<=MAXM;j++){
if(dis[l[j].u]+w[j]<dis[l[j].v]){
dis[l[j].v]=dis[l[j].u]+w[j];//核心代码
}
}
}
//算法结束,dis[i]就是s点到i点的最短路,若dis[i]==0x3f3f3f3f则从s点无法到达该点。
ford算法很好理解,容易看出是一个一维Dp(实际上还有二维dp写法,蒟蒻不会……)。
以下是几个常见不理解的问题:
为什么distance初始化除起点外设成正无穷?
这个……肯定是为了接下来的更新啊!
对于无向图和有向图,这个算法需要变化吗?
说到点上了!对于有向图一定要记住,伪代码中的u,一定是边的入节点!相应的v,一定是出节点!
如果是无向图,我们需要做的就是反过来再执行一次。
也就是原来是这个:
if(dis[l[j].u]+w[j]<dis[l[j].v])dis[l[j].v]=dis[l[j].u]+w[j];
变成了这个:
if(dis[l[j].u]+w[j]<dis[l[j].v])dis[l[j].v]=dis[l[j].u]+w[j];
if(dis[l[j].v]+w[j]<dis[l[j].u])dis[l[j].u]=dis[l[j].v]+w[j];
到底什么是所谓的松弛操作?
松弛操作,很简单,就是这句代码:
if(dis[l[j].u]+w[j]<dis[l[j].v])dis[l[j].v]=dis[l[j].u]+w[j];
惊不惊喜?
原来听了这么久松弛,还以为是啥奇怪的东西,没想到已经用上了!
为什么外层循环要用n次?
这个嘛……实际上仔细想想可以发现,运用蓝白点的思想,一开始起点S是白点,其他都是蓝点。然后由于如果还有蓝点,那么一定还有边连接着蓝点和白点。每次外层循环一定可以遍历到一些这样的边,也一定至少有一个蓝点变成白点。
这样的话,我们执行n遍外层循环,一定能保证所有点都求出了最终结果。
为什么说它不适用于负权回路?
负权回路是什么?
负权回路是指,图上一个回路,各边权值之和是负数。
相信看到这里你已经发现,如果图上存在负权回路,那么至少有两点间的最短路会是无限小!
因为可以绕这个回路走无限圈,最短路也跟着无限小……
所以:存在负权回路的图无法求出最短路。
注意是无法!目前已知算法都无法!
bellman-ford算法可以在算法结束时给出错误提示,以判断这张图是否存在负权回路:
方法:在核心代码全部结束后,执行以下代码,若仍存在某条边,使得dis[l[j].u]+w[j]<dis[l[j].v]
那么我们可以判定该图存在负权回路:
for(int i=1;i<=MAXM;i++){
if(dis[l[j].u]+w[j]<dis[l[j].v])//错误提示。
}
挣扎着优化 ∑( 口 ||
对bellman算法,我们还可以有一个优化,我们看到,bellman算法有的时候会在外层循环没结束的时候就完成了所有松弛操作!
所以我们可以加一个计数:记下每次大循环中松弛的次数,当某次循环不进行松弛时,我们认定算法结束,直接跳出大循环。
#define MAXN 最大点数
#define MAXM 最大边数
int dis[MAXN],w[MAXM],s;
struct lines{
int u,v;
}l[MAXM];
int tot;
for(int i=1;i<=MAXN;i++){
tot=0;//变动
for(int j=1;j<=MAXM;j++){
if(dis[l[j].u]+w[j]<dis[l[j].v]){
tot++;//变动
dis[l[j].v]=dis[l[j].u]+w[j];
}
}
if(!tot)break;//变动
}
而这个小小优化,有什么作用呢?
70pts -> 100pts
AC记录
一个小操作,可以顺利通过这道题(虽然是弱化版)
劣势
bellman-ford算法的缺点其实刚刚已经体现出来了!
就是,外层循环有大量重复计算!
蒟蒻过几天会写一个SPFA的讲解,SPFA其实就是ford的队列优化。
完结撒花
算法之SPFA的前置:Bellman-Ford算法的更多相关文章
- 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 ...
- 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算法以及SPFA算法
说完dijkstra算法,有提到过朴素dij算法无法处理负权边的情况,这里就需要用到Bellman-Ford算法,抛弃贪心的想法,牺牲时间的基础上,换取负权有向图的处理正确. 单源最短路径 Bellm ...
- 图论之最短路算法之SPFA算法
SPFA(Shortest Path Faster Algorithm)算法,是一种求最短路的算法. SPFA的思路及写法和BFS有相同的地方,我就举一道例题(洛谷--P3371 [模板]单源最短路径 ...
- HDOJ 2544 最短路(最短路径 dijkstra算法,SPFA邻接表实现,floyd算法)
最短路 Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submis ...
- Bellman-ford算法、SPFA算法求解最短路模板
Bellman-ford 算法适用于含有负权边的最短路求解,复杂度是O( VE ),其原理是依次对每条边进行松弛操作,重复这个操作E-1次后则一定得到最短路,如果还能继续松弛,则有负环.这是因为最长的 ...
随机推荐
- "一键重装系统软件"操作流程
博主之前重装系统都是直接用win10系统更新里的重置系统(版本不会变化),和U盘重装电脑出厂映像(有各种品牌自带的软件,而且由于是出场版本,版本很低) 所以这次用"小白一键重装系统" ...
- 基于JESD204B和PCIe DMA的多通道数据采集和回放系统
基于JESD204B和PCIe DMA的多通道数据采集和回放系统 在主机端PCIe驱动的控制和调度下,数据采集与回放系统可以同时完成对多个JESD204B接口AD数据的采集以及JESD204B接口DA ...
- Vivado_8位流水灯
Design 代码中的计数器设置是因为我的开发板的时钟是100MHZ的,也就是1秒完成了100_000_000次时钟信号,所以我设置计数器为100_000_000次. 也就是说,我让流水灯的变化周期为 ...
- 树上启发式合并(dsu on tree)
树上启发式合并属于暴力的优化,复杂度O(nlogn) 主要解决的问题特点在于: 1.对于树上的某些信息进行查询 2.一般问题的解决不包含对树的修改,所有答案可以离线解决 算法思路:这类问题的特点在于父 ...
- 修改Oracle共享池大小
1. sysdba登录数据库 [oracle@ufdb165 ~]$ sqlplus /nolog SQL*Plus: Release 11.2.0.4.0 Production on Wed Au ...
- IO学习笔记
IO File 概述 构造方法 代码实现: public class FileDemo001 { public static void main(String[] args) { File f1 = ...
- C#程序自启动
在窗体加载事件里面加入下述代码: //设置开机自启动 RegistryKey registryKey = Registry.CurrentUser.OpenSubKey ("SOFTWARE ...
- 解决"raise EnvironmentError("%s not found" % (_mysql_config_path,)) OSError: mysql_config not found"报错
redhat系(如centos) yum install mysql-devel debain系(如ubuntu) sudo apt-get install libmysqlclient-dev
- vue阻止向上和向下冒泡
阻止向下冒泡 <div class="content" @click.self="cancelFunc"></div> 阻止向上冒泡 & ...
- day25 前端
https://www.dcloud.io/hbuilderx.html 下载HbuilderX,直接解压缩双击打开 html5 <!DOCTYPE html><!-- 文档类型,声 ...