spfa算法及判负环详解
spfa (Shortest Path Faster Algorithm)
是一种单源最短路径的算法,基于Bellman-Ford算法上由队列优化实现。
什么是Bellman_Ford,百度内食用QWQ
也就是说,Bellman_Ford是一种无脑,疯狂松弛的算法。其复杂度为O(nm),可想而知,对于上万的数据会炸的一塌糊涂。。。
相对而言,SPFA显得就没那么无脑了。
在Bellman_Ford算法上,我们找到了一种优化松弛的方法:对于其子边没有进行松弛的松弛操作,当前操作不可能得出正确结果,只能需要后期子边全部被松弛为最佳结果后再进行松弛得到当前边的最佳结果。
那么,在理解这个后,我们搞一个队列来优化Bellman_Ford。具体的,对于已经被松弛过的点,我们将其入队去更新其他的点,这样相对于原来用没有被优化更新的点去更新其他点来说更优。在当前点优化完其他点后,将其出队,以后也可以进队,用来优化其他边。如此循环往复直到队列为空(没有可以优化的点了),那么求出来的就是最短路。
代码,来源于单源最短路径弱化版。
// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#define spfa zhx_ak_ioi using namespace std; const long long inf=; long long n,m,s;
long long dis[],vis[],head[],num_edge=; struct Edge{
long long next,to,dis;
}edge[]; queue <long long> q; void addedge(long long from,long long to,long long dis)
{
num_edge++;
edge[num_edge].next=head[from];
edge[num_edge].to=to;
edge[num_edge].dis=dis;
head[from]=num_edge;
} void spfa()
{
for(long long i=;i<=n;++i)
{
dis[i]=inf;
vis[i]=;
}
dis[s]=;
vis[s]=;
q.push(s);
while(!q.empty())
{
long long u=q.front();
q.pop();
vis[u]=;
for(long long i=head[u];i;i=edge[i].next)
{
long long zhongdian=edge[i].to;
if(dis[zhongdian]>dis[u]+edge[i].dis)
{
dis[zhongdian]=dis[u]+edge[i].dis;
if(!vis[zhongdian])
{
q.push(zhongdian);
vis[zhongdian]=;
}
}
}
}
} int main()
{
scanf("%lld %lld %lld",&n,&m,&s);
for(long long i=;i<=m;++i)
{
long long u,v,w;
scanf("%lld %lld %lld",&u,&v,&w);
addedge(u,v,w);
}
spfa();
for(long long i=;i<=n;++i)
{
if(i==s) printf("0 ");
else printf("%lld ",dis[i]);
}
return ;
}
判断负环:
spfa和Bellman_Ford算法可以用来判断负环。
负环,就是图上一个边权权值和为负数的环,
BFS广搜判断方法
对于一个不存在负环的图,从起点到任意一个点最短距离经过的点最多只有n个。那么定义一个cnt数组,表示当前点从起点(编号设为1)到点i的最短距离包含点的个数。如果一个cnt的值大于n的话,就可以判断负环了。同样的,对于每一次松弛操作,一旦松弛成功,我们就将下一个点的cnt值+1,对于环,我们每次松弛时直接判断cnt值是不是大于n,如果大于,说明找到了负环,那么我们就可以退出直接输出就行。
但是,在找负环时,广搜的性质决定了它的复杂度上并不适合找负环。原因:负环本质上是一条环形链(可以这么想但不一定严谨。),但是BFS考虑面太广了以至于在判环的操作上会考虑其他的不属于这个环的元素,因此搜完整个环的效率会变慢。那么有什么算法能够在遍历到这条链?的时候能够不分心的一口气走到底呢?DFS。
代码就是在原spfa上加入cnt和判断操作。
DFS深搜判断负环方法
与BFS唯一不同就是把队列换成了栈,取刚更新的点一口气继续更新到底。这样就可以一直在环上跑,几圈下来就可以判断并退出了。。
代码就是把BFS代码上换个数据结构。
你问我为什么这个代码中没有出现有关边的负权的判断?
在这上面
如果是负数的话那个条件就可以无限满足并(转圈圈跑)了。
完结。QWQ
spfa算法及判负环详解的更多相关文章
- SPFA算法的判负环问题(BFS与DFS实现)
经过笔者的多次实践(失败),在此温馨提示:用SPFA判负环时一定要特别小心! 首先SPFA有BFS和DFS两种实现方式,两者的判负环方式也是不同的. BFS是用一个num数组,num[x] ...
- poj3259 Wormholes (判负环)【spfa】(模板)
<题目链接> 题目大意: John的农场里N块地,M条路连接两块地,W个虫洞,虫洞是一条单向路,会在你离开之前把你传送到目的地,就是当你过去的时候时间会倒退Ts.我们的任务是知道会不会在从 ...
- [poj3259]Wormholes(spfa判负环)
题意:有向图判负环. 解题关键:spfa算法+hash判负圈. spfa判断负环:若一个点入队次数大于节点数,则存在负环. 两点间如果有最短路,那么每个结点最多经过一次,这条路不超过$n-1$条边. ...
- 浅谈SPFA判负环
目录 SPFA判负环 [前言] [不可代替性] [具体实现] SPFA的过程 判负环 [核心代码] [例题] SPFA判负环 有不足的地方请指出 本蒟蒻一定会修改吼 [前言] 最短路的求法中最广为人知 ...
- BZOJ.4500.矩阵(差分约束 SPFA判负环 / 带权并查集)
BZOJ 差分约束: 我是谁,差分约束是啥,这是哪 太真实了= = 插个广告:这里有差分约束详解. 记\(r_i\)为第\(i\)行整体加了多少的权值,\(c_i\)为第\(i\)列整体加了多少权值, ...
- BZOJ 4898 [APIO2017] 商旅 | SPFA判负环 分数规划
BZOJ 4898 [APIO2017] 商旅 | SPFA判负环 分数规划 更清真的题面链接:https://files.cnblogs.com/files/winmt/merchant%28zh_ ...
- [P1768]天路(分数规划+SPFA判负环)
题目描述 “那是一条神奇的天路诶~,把第一个神犇送上天堂~”,XDM先生唱着这首“亲切”的歌曲,一道猥琐题目的灵感在脑中出现了. 和C_SUNSHINE大神商量后,这道猥琐的题目终于出现在本次试题上了 ...
- 【原创】SPFA判负环
[定义与概念] 给定一张有向图,若其中存在一个环的所有权值之和为负数,这个环称为负环. [算法实现] 当然,负环的求解可以暴搜,但是时间复杂度就难以入眼了,我们回到求解单源最短路径算法上面,看看它们能 ...
- poj 3621 二分+spfa判负环
http://poj.org/problem?id=3621 求一个环的{点权和}除以{边权和},使得那个环在所有环中{点权和}除以{边权和}最大. 0/1整数划分问题 令在一个环里,点权为v[i], ...
随机推荐
- Python之Numpy:线性代数/矩阵运算
当你知道工具的用处,理论与工具如何结合的时候,通常会加速咱们对两者的学习效率. 零 numpy 那么,Numpy是什么? NumPy(Numerical Python) 是 Python 语言的一个扩 ...
- centOS7忘记密码,修改root账号密码
centOS7忘记密码,修改root账号密码 RHEL7 的世界发生了变化,重置 root 密码的方式也一样.虽然中断引导过程的旧方法(init=/bin/bash)仍然有效,但它不再是推荐的.“Sy ...
- three中的着色器示例
其实在3D引擎/库的帮助下,我们做webgl开发的难度已经很大大地降低了,熟悉相关API的话,开发一个简单的3D程序可以说是很轻松的事情. 在我看来,webgl的核心就是着色器(顶点着色器.片元着色器 ...
- php 通过mysqli 操作数据库mysql
目录 php mysqli 操作数据库 连接数据库 通过mysqli 创建数据库 通过mysqi 创建数据表 通过mysqli向数据表中插入信息 通过mysqli 读取数据 where语句的应用 通过 ...
- EMA指数平滑移动平均
英文参考:http://www.incrediblecharts.com/indicators/exponential_moving_average.php Exponential moving av ...
- kibana 查询例子
1.数字比较和布尔查询 account_number:< AND balance:>
- redhat 7 防火墙配置
没有iptables 用systemctl stop firewalld
- 针对yarn的8088端口攻击
参考: https://www.wangbokun.com/%E8%BF%90%E7%BB%B4/2019/09/02/%E6%8C%96%E7%9F%BF%E7%97%85%E6%AF%92.htm ...
- Luogu P4878 [USACO05DEC]布局
题目 差分约束模板. 注意判负环需要建一个超级源点到每个点连一条\(0\)的边.因为\(1\)不一定能到达所有的点. #include<bits/stdc++.h> #define pi ...
- 分层最短路(牛客第四场)-- free
题意: 给你边权,起点和终点,有k次机会把某条路变为0,问你最短路是多长. 思路: 分层最短路模板题.题目有点坑(卡掉了SPFA,只能用dijkstra跑的算法). #include<iostr ...