SPFA ------队列优化的Bellman-Ford

由Bellman-Ford算法实现带有负权边的单源最短路,时间复杂度是O(VE),也就是边数乘顶点数。但是根据Bellman-Ford的状态转移方程$$dist[i] = min(dist[i] , last[k] + w[k -> i])$$可知,当且仅当顶点k的dist值在上一层有更新时,在本层更新时顶点 i 的dist值才有可能变小。因此SPFA出现了

SPFA算法相较于Bellman-Ford多维护了一个队列,队列中存储可能使得最短路获得更新的顶点。每次更新我们仅使用队列中的顶点来进行更新,同时每次将更新过的顶点加入队列,这样就避免了无用的更新操作。

SPFA求带负权边的单源最短路

给出例题851. spfa求最短路 - AcWing题库

#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int N = 1e5+20;
int n,m;
vector<pair<int,int>> g[N];
int dist[N];
bool st[N]; //判断该顶点是否已经在队列中,防止重复入队
void spfa()
{
memset(dist,0x3f,sizeof dist);
dist[1] = 0;
queue<int> q;
q.push(1); //将源点加入队列中
st[1] = true;
while(q.size())
{
int k = q.front();
q.pop();
st[k] = false; //出队后状态置为false
for(auto x : g[k])
{
int v = x.first, w = x.second;
if(dist[v] > dist[k] + w)
{
dist[v] = dist[k] + w;
if(!st[v]) //防止重复入队
{
q.push(v);
st[v] = true;
}
}
}
} }
int main()
{
cin >> n >> m;
while(m --)
{
int x,y,z;
cin >> x >> y >> z;
g[x].push_back({y,z});
}
spfa();
if(dist[n] > 0x3f3f3f3f/2) puts("impossible");
else cout << dist[n];
return 0;
}
SPFA判断图中是否有负环

和Bellman-Ford一样,当图中出现负环时(如下图)

flowchart LR
A((A)) -->|2| B((B))
B -->|-5| C((C))
C -->|1| A

根据从源点到目标点的最短路至多经过n-1条边,当存在负环时,更新操作可以一直进行,也就是说边数会大于n-1。我们只需要监视在更新过程中是否出现经过边数大于n-1即可。

如下题

852. spfa判断负环 - AcWing题库

代码如下

#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int N = 2500;
vector<pair<int,int>> g[N];
int dist[N];
int st[N],cnt[N];
int n,m;
bool spfa()
{
queue<int> q;
for(int i = 1 ; i <= n ; i++)
{
q.push(i);
st[i] = true;
}
while(q.size())
{
int k = q.front();
q.pop();
st[k] = false;
for(auto x : g[k])
{
int v = x.first, w = x.second;
if(dist[v] > dist[k] + w)
{
dist[v] = dist[k] + w;
cnt[v] = cnt[k] + 1;
if(cnt[v] >= n)
return true;
if(!st[v])
{
q.push(v);
st[v] = true;
}
}
}
}
return false;
}
int main()
{
cin >> n >>m;
while(m --)
{
int x,y,z;
cin >> x >> y >> z;
g[x].push_back({y,z});
}
if(spfa())
cout << "Yes";
else
cout << "No";
return 0;
}

几点细节

  1. 这里开始将所有顶点都入队,是因为若仅使用一个源点的话,出现孤立的不连通块会使得我们在找负环或者说更新最短路时有疏漏。因此初始将所有顶点加入队列,且不用初始化dist数组。因为我们目标是找出负值圈,而如果有负值圈,最短路会小于0且会一直更新,也就是说队列永远不会空,且dist会一直减小。我们只需要在某个节点检测到cnt[v] >= n即可
  2. 以上将所有顶点入队的操作也可以理解为有一个虚拟的源点s,其与图中各个点都有一条权值为0的点,也就说该虚拟源点使得图联通起来。然后使用该虚拟源点更新就是将各个顶点加入队列。
  3. 关于cnt[v] = cnt[k] + 1。显然若k顶点能够更新dist[v],那么顶点v的最短路所经过的边数即为顶点k所经过的边数加上更新的这条边数。

SPFA -----队列优化的Bellman-Ford的更多相关文章

  1. SPFA队列优化

    spfa队列优化(用来求最短路) 实现方法: 1.存入图.可以使用链式前向星或者vocter. 2.开一个队列,先将开始的节点放入. 3.每次从队列中取出一个节点X,遍历与X相通的Y节点,查询比对   ...

  2. 最短路--spfa+队列优化模板

    spfa普通版就不写了,优化还是要的昂,spfa是可以判负环,接受负权边和重边的,判断负环只需要另开一个数组记录每个结点的入队次数,当有任意一个结点入队大于点数就表明有负环存在 #include< ...

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

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

  4. 关于SPFA的双端队列优化

    7.11 Update 我做题的时候发现这样写会RE 因为在使用双端队列优化SPFA的时候 在将一个点加入队列的时候,如果队列已经空了 那么一旦出现dis[Q.front()]就会RE 可以这样修改 ...

  5. HDU 2544 最短路(floyd+bellman-ford+spfa+dijkstra队列优化)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544 题目大意:找点1到点n的最短路(无向图) 练一下最短路... dijkstra+队列优化: #i ...

  6. 队列优化dijsktra(SPFA)的玄学优化

    转载:大佬博客 最近想到了许多优化spfa的方法,这里想写个日报与大家探讨下 前置知识:spfa(不带任何优化) 由于使用较多 STLSTL ,本文中所有代码的评测均开启 O_2O2​ 优化 对一些数 ...

  7. poj 3259 Wormholes : spfa 双端队列优化 判负环 O(k*E)

    /** problem: http://poj.org/problem?id=3259 spfa判负环: 当有个点被松弛了n次,则这个点必定为负环中的一个点(n为点的个数) spfa双端队列优化: 维 ...

  8. Bellman-Ford算法及其队列优化(SPFA)

    一.算法概述 Bellman-Ford算法解决的是一般情况下的单源最短路径问题.所谓单源最短路径问题:给定一个图G=(V,E),我们希望找到从给定源结点s属于V到每个结点v属于V的最短路径.单源最短路 ...

  9. SPFA(Bellman-Ford队列优化)

    原理:队列+松弛操作 将源点加入队尾,每一步读取队头顶点u,并将队头顶点u出队(记得消除标记):将与点u相连的所有点v进行松弛操作,如果能更新距离(即令d[v]变小),那么就更新,另外,如果点v没有在 ...

  10. 图论之最短路径(3)队列优化的Bellman-Ford算法(SPFA算法)

    在Bellman-Ford算法中 我们可以看到大量的优化空间:如果一个点的最短路径已经确定了,那么它就不会再改变,因此不需要再处理.换句话说:我们每次只对最短路径改变了的顶点的所有出边进行操作 使用一 ...

随机推荐

  1. 深度学习(六)——神经网络的基本骨架:nn.Module的使用

    一.torch.nn简介 官网地址: torch.nn - PyTorch 2.0 documentation 1. torch.nn中的函数简介 Containers:神经网络的骨架 Convolu ...

  2. uniapp#实现自定义省市区三级联动

    uni-APP中的三级联动(省市区)---数据前端写死 https://blog.csdn.net/lwaner/article/details/107150805 uniapp#实现自定义省市区三级 ...

  3. 淘宝flexible.js源码分析

    下面三种情况都会刷新页面,都会触发load事件. 1.a标签的超链接. 2.F5或者刷新按钮(强制刷新) 3.前进后退按钮 但是火狐中,有个特点,有个"往返缓存",这个缓存中不仅保 ...

  4. java基础(12)--static变量/方法 与 无 static的变量/方法的区别

    一.static方法与非static方法的区别: 1.带有static方法调用:使用类名.方法名(),(建议,但也支持,"引用".变量的方式访问) 2.没有static方法调用(实 ...

  5. [转帖]【TiDB】快速起步

    1. 存储引擎的的功能 提供数据存储接口并持久化存储数据 2. LSM-tree 的特性 LSM-tree 结构本质上是一个用空间置换写入延迟,用顺序写入替换随机写入的数据结构 3. 数据库技术的发展 ...

  6. [转帖]基于 Skywalking 部署应用性能监控

    https://www.jianshu.com/p/50627b9ab0be 今天我们就着重讲一讲如何基于 Skywalking 来快速搭建一套应用性能监控平台   walkingfunny.com. ...

  7. Springboot tomcat.threads线程数学习

    Springboot tomcat.threads线程数学习 摘要 压测完nginx 突然想搞一下springboot内嵌的tomcat的 threads的参数 一不做二不休, 直接就着脚本进行学习和 ...

  8. [转帖]linux中top命令显示不全怎么解决

    https://www.yisu.com/zixun/697775.html 这篇"linux中top命令显示不全怎么解决"文章的知识点大部分人都不太理解,所以小编给大家总结了以下 ...

  9. 行云部署成长之路--慢SQL优化之旅 | 京东云技术团队

    ​ 当项目的SQL查询慢得像蜗牛爬行时,用户的耐心也在一点点被消耗,作为研发,我们可不想看到这样的事.这篇文章将结合行云部署项目的实践经验,带你走进SQL优化的奇妙世界,一起探索如何让那些龟速的查询飞 ...

  10. Lectures

    Copy and Paste 3(P9523) Problem Solution 转移方程中的"父问题枚举子问题寻找转移"可以转成"子问题寻找父问题主动转移"处 ...