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算法的更多相关文章

  1. Bellman—Ford算法思想

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

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

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

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

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

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

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

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

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

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

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

  7. 最短路径——Bellman-Ford算法以及SPFA算法

    说完dijkstra算法,有提到过朴素dij算法无法处理负权边的情况,这里就需要用到Bellman-Ford算法,抛弃贪心的想法,牺牲时间的基础上,换取负权有向图的处理正确. 单源最短路径 Bellm ...

  8. 图论之最短路算法之SPFA算法

    SPFA(Shortest Path Faster Algorithm)算法,是一种求最短路的算法. SPFA的思路及写法和BFS有相同的地方,我就举一道例题(洛谷--P3371 [模板]单源最短路径 ...

  9. HDOJ 2544 最短路(最短路径 dijkstra算法,SPFA邻接表实现,floyd算法)

    最短路 Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submis ...

  10. Bellman-ford算法、SPFA算法求解最短路模板

    Bellman-ford 算法适用于含有负权边的最短路求解,复杂度是O( VE ),其原理是依次对每条边进行松弛操作,重复这个操作E-1次后则一定得到最短路,如果还能继续松弛,则有负环.这是因为最长的 ...

随机推荐

  1. 齐博x1标签实例:标签如何调用论坛内容

    论坛的内容不像CMS其它模块可以直接用变量 {$rs.content} 因为论坛的内容数据表是放在另一个表的,单独分开的. 当前也是为了考试效率问题而这样设计的. 所以他的调用要用下面的代码 {:fu ...

  2. 函数柯里化实现sum函数

    需求 实现sum函数,使其可以传入不定长参数,以及不定次数调用 //示例 console.log(sum(1,2)(3)()) //6 console.log(sum(2,3,4,5)(1,2)(3) ...

  3. 前端无法渲染CSS文件

    问题描述: 启动前端后,发现前端的页面渲染不符合预期,看情况应该是css文件没有生效. 排查步骤: 查看有无报错信息. 查看后台输出,没有可用的提示信息,如图: 确认 css 的路径没错. 前端打包后 ...

  4. 【UML】统一建模语言

    如果是准备学习设计模式的同学,可以只了解类图相关的知识 而如果是在准备软件设计师考试的同学,或许会对你有点帮助 正在施工...... 参考博客:https://blog.csdn.net/unique ...

  5. JS中数值类型的本质

    一.JS中的数值类型 众所JS爱好友周知,JS中只有一个总的数值类型--number,它包含了整型.浮点型等数值类型.其中,浮点数的实现思想有点复杂,它把一个数拆成两部分来存储.第一部分是有效位数,也 ...

  6. fastjson反序列化漏洞历史CVE学习整理

    fastjson 1.2.24反序列化漏洞复现 先写一个正常的使用 fastjson的web服务 我们使用 springboot创建 主要是pom.xml 里面要添加fastjson fastjson ...

  7. .NET性能优化-复用StringBuilder

    在之前的文章中,我们介绍了dotnet在字符串拼接时可以使用的一些性能优化技巧.比如: 为StringBuilder设置Buffer初始大小 使用ValueStringBuilder等等 不过这些都多 ...

  8. ssh明文密码小工具:sshpass

    Xshell 远程时可以用如下方式进行明文密码免交互登陆: ssh 用户:密码@ip 可换到linux时,就不行了,在某些不适合使用公钥免密的情况下,到底该怎样免交互登陆? 于是我找到了sshpass ...

  9. 移动 VR 开发时要避免的 PC 渲染技术

    更新:本文是为 Quest 1 开发人员编写的.虽然 Quest 2 建立在相同的架构上,但现在更容易为阴影贴图(以及其他需要从先前渲染过程中生成的纹理读取的简单技术)做预算. 尽管移动芯片组可以支持 ...

  10. Python异步协程(asyncio详解)

    续上篇讲解yield from博客,上篇链接:https://www.cnblogs.com/Red-Sun/p/16889182.html PS:本博客是个人笔记分享,不需要扫码加群或必须关注什么的 ...