SPFA -----队列优化的Bellman-Ford
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求带负权边的单源最短路
#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一样,当图中出现负环时(如下图)
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;
}
几点细节
- 这里开始将所有顶点都入队,是因为若仅使用一个源点的话,出现孤立的不连通块会使得我们在找负环或者说更新最短路时有疏漏。因此初始将所有顶点加入队列,且不用初始化dist数组。因为我们目标是找出负值圈,而如果有负值圈,最短路会小于0且会一直更新,也就是说队列永远不会空,且dist会一直减小。我们只需要在某个节点检测到cnt[v] >= n即可
- 以上将所有顶点入队的操作也可以理解为有一个虚拟的源点s,其与图中各个点都有一条权值为0的点,也就说该虚拟源点使得图联通起来。然后使用该虚拟源点更新就是将各个顶点加入队列。
- 关于cnt[v] = cnt[k] + 1。显然若k顶点能够更新dist[v],那么顶点v的最短路所经过的边数即为顶点k所经过的边数加上更新的这条边数。
SPFA -----队列优化的Bellman-Ford的更多相关文章
- SPFA队列优化
spfa队列优化(用来求最短路) 实现方法: 1.存入图.可以使用链式前向星或者vocter. 2.开一个队列,先将开始的节点放入. 3.每次从队列中取出一个节点X,遍历与X相通的Y节点,查询比对 ...
- 最短路--spfa+队列优化模板
spfa普通版就不写了,优化还是要的昂,spfa是可以判负环,接受负权边和重边的,判断负环只需要另开一个数组记录每个结点的入队次数,当有任意一个结点入队大于点数就表明有负环存在 #include< ...
- poj1860 bellman—ford队列优化 Currency Exchange
Currency Exchange Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 22123 Accepted: 799 ...
- 关于SPFA的双端队列优化
7.11 Update 我做题的时候发现这样写会RE 因为在使用双端队列优化SPFA的时候 在将一个点加入队列的时候,如果队列已经空了 那么一旦出现dis[Q.front()]就会RE 可以这样修改 ...
- HDU 2544 最短路(floyd+bellman-ford+spfa+dijkstra队列优化)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2544 题目大意:找点1到点n的最短路(无向图) 练一下最短路... dijkstra+队列优化: #i ...
- 队列优化dijsktra(SPFA)的玄学优化
转载:大佬博客 最近想到了许多优化spfa的方法,这里想写个日报与大家探讨下 前置知识:spfa(不带任何优化) 由于使用较多 STLSTL ,本文中所有代码的评测均开启 O_2O2 优化 对一些数 ...
- poj 3259 Wormholes : spfa 双端队列优化 判负环 O(k*E)
/** problem: http://poj.org/problem?id=3259 spfa判负环: 当有个点被松弛了n次,则这个点必定为负环中的一个点(n为点的个数) spfa双端队列优化: 维 ...
- Bellman-Ford算法及其队列优化(SPFA)
一.算法概述 Bellman-Ford算法解决的是一般情况下的单源最短路径问题.所谓单源最短路径问题:给定一个图G=(V,E),我们希望找到从给定源结点s属于V到每个结点v属于V的最短路径.单源最短路 ...
- SPFA(Bellman-Ford队列优化)
原理:队列+松弛操作 将源点加入队尾,每一步读取队头顶点u,并将队头顶点u出队(记得消除标记):将与点u相连的所有点v进行松弛操作,如果能更新距离(即令d[v]变小),那么就更新,另外,如果点v没有在 ...
- 图论之最短路径(3)队列优化的Bellman-Ford算法(SPFA算法)
在Bellman-Ford算法中 我们可以看到大量的优化空间:如果一个点的最短路径已经确定了,那么它就不会再改变,因此不需要再处理.换句话说:我们每次只对最短路径改变了的顶点的所有出边进行操作 使用一 ...
随机推荐
- SpringCloud学习 系列七、EurekaServer集群创建
系列导航 SpringCloud学习 系列一. 前言-为什么要学习微服务 SpringCloud学习 系列二. 简介 SpringCloud学习 系列三. 创建一个没有使用springCloud的服务 ...
- mongose查询
- SD-Host控制器设计架构
SD Host功能列表 SD Host挂接在SoC中,与外部的SD card进行交互 有控制寄存器和状态寄存器,SoC往往有CPU,通过CPU进行配置寄存器,有些SoC没有CPU,需要使用I2C或者S ...
- 基于AHB_BUS的eFlash控制器设计-软硬件系统设计
eFlash软硬件系统设计 软硬件划分 划分好软硬件之后,IP暴露给软件的寄存器和时序如何? 文档体系:详细介绍eflash控制器的设计文档 RTL代码编写:详细介绍eflash控制器的RTL代码 1 ...
- C++初始化列表时,形参和实参名可以一样,编译器可以识别
在这里初始化列表直接用age(age)即可,用this->age(age)反而会出错,C++不允许在成员初始化列表中使用this关键字来初始化类成员 class Person { public: ...
- 【Hash】字符串哈希
Hash 的核心思想在于,将输入映射到一个值域较小.可以方便比较的范围,典型的用法就是将资源紧张的设备中的不定长字符串转化为定长整数,以达到节省空间的目的 如:printf("This is ...
- 神经网络优化篇:详解局部最优的问题(The problem of local optima)
局部最优的问题 在深度学习研究早期,人们总是担心优化算法会困在极差的局部最优,不过随着深度学习理论不断发展,对局部最优的理解也发生了改变.向展示一下现在怎么看待局部最优以及深度学习中的优化问题. 这是 ...
- [转帖]聊聊字符串数据长度和nls_length_semantics参数
字符串是我们设计数据库经常用到的类型,从传统的ASCII格式到UTF-8格式,不同应用需求对应不同的字符类型和长度配置.针对Oracle而言,最常用的类型无外乎char和varchar2两个基本类型. ...
- 一键部署Docker中间件简单方法-redis为例
一键部署Docker中间件简单方法-redis为例 背景 想能够快速部署一些中间件. 写文档虽然可以, 但是总会有人问, 能够一键部署应该最好不过. 下载以及导出镜像 docker pull redi ...
- [转帖]记录一则enq: TX - row lock contention的分析过程
https://www.cnblogs.com/jyzhao/p/8628184.html 故障描述:与客户沟通,初步确认故障范围大概是在上午的8:30-10:30之间,反应故障现象是Tomcat的连 ...