【原创】SPFA判负环
【定义与概念】
给定一张有向图,若其中存在一个环的所有权值之和为负数,这个环称为负环。
【算法实现】
当然,负环的求解可以暴搜,但是时间复杂度就难以入眼了,我们回到求解单源最短路径算法上面,看看它们能否求解。
我们知道
| 算法名称 | 能否处理负边 | 时间复杂度 |
| Dijkstra | 不能,负权的存在使得最短路径不一定最短 | O(n^2) |
| 堆优化Dijkstra | 不能,如上 | O(mlogn) |
| Bellman-Ford | 能 | O(nm) |
| SPFA | 能 | O(km) |
我们主要使用SPFA,讲一下SPFA判断负环。
SPFA有三种以上的方法判断负环:
- 设cnt[x]表示1~x的最短路径包含边数,cnt[1]=0。当收敛边权(判断三角形不等式)时,更新cnt[y]=cnt[x]+1。如果某时cnt[x]>=边的总数m,说明存在负环。
- 记录每个点入队的次数,如果某个点入队次数超过点的总数n,说明存在最小环。
- 卡时判负环,判负环最骚的操作。给队列总长度做限制,超过限制说明有环。至于这个限制具体是什么,请去问玄学,我不知道。
给出第一、二种解法的参考吧。
拿道板子题出来。
P3385 【模板】负环
注意这道题鬼畜的输出。。。
这是第一种: 573ms / 5.04MB AC
#include<cstdio>
#include<iostream>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstring>
#include<vector>
#include<ctime>
#define N 10010
using namespace std;
priority_queue<int,vector<int>,greater<int> > q;
int head[N],tot,n,m,d[N],cnt[N];
struct rec{
int next,ver,edge;
}g[N<<];
void add(int x,int y,int val){
g[++tot].ver=y,g[tot].edge=val;
g[tot].next=head[x],head[x]=tot;
}
bool spfa(int x)
{
memset(d,0x3f,sizeof(d));
memset(cnt,,sizeof(cnt));
d[x]=;cnt[x]=;
q.push(x);
while(q.size())
{
int index=q.top();q.pop();
for(int i=head[index];i;i=g[i].next){
int y=g[i].ver,z=g[i].edge;
if(d[y]>d[index]+z){
d[y]=d[index]+z;
cnt[y]=cnt[index]+;
if(cnt[y]>=m) return ;
q.push(y);
}
}
}
return ;
}
int main()
{
int t;
cin>>t;
while(t--)
{
memset(g,,sizeof(g));
memset(head,,sizeof(head));
if(!q.empty()) q.pop();
tot=;
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
int x,y,val;
scanf("%d%d%d",&x,&y,&val);
if(val<) add(x,y,val);
else add(x,y,val),add(y,x,val);
}
if(spfa()) cout<<"YE5"<<endl;
else cout<<"N0"<<endl;
}
return ;
}
这是第二种:1965ms / 9.04MB 91pnts
#include<cstdio>
#include<iostream>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstring>
#include<vector>
#define N 10010
using namespace std;
priority_queue<int,vector<int>,greater<int> > q;
int head[N],tot,n,m,d[N],cnt[N];
struct rec{
int next,ver,edge;
}g[N<<];
void add(int x,int y,int val){
g[++tot].ver=y,g[tot].edge=val;
g[tot].next=head[x],head[x]=tot;
}
bool spfa(int x)
{
memset(v,,sizeof(v));
memset(d,0x3f,sizeof(d));
memset(cnt,,sizeof(cnt));
d[x]=;cnt[x]=;
q.push(x);
while(q.size())
{
int index=q.top();q.pop();
for(int i=head[index];i;i=g[i].next){
int y=g[i].ver,z=g[i].edge;
if(d[y]>d[index]+z){
d[y]=d[index]+z;
if(cnt[y]>=n) return ;
cnt[y]++,q.push(y),v[y]=;
}
}
}
return ;
}
int main()
{
int t;
cin>>t;
while(t--)
{
memset(g,,sizeof(g));
memset(head,,sizeof(head));
if(!q.empty()) q.pop();
tot=;
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
int x,y,val;
scanf("%d%d%d",&x,&y,&val);
if(val<) add(x,y,val);
else add(x,y,val),add(y,x,val);
}
if(spfa()) cout<<"YE5"<<endl;
else cout<<"N0"<<endl;
}
return ;
}
【原创】SPFA判负环的更多相关文章
- POJ 3259 Wormholes(SPFA判负环)
题目链接:http://poj.org/problem?id=3259 题目大意是给你n个点,m条双向边,w条负权单向边.问你是否有负环(虫洞). 这个就是spfa判负环的模版题,中间的cnt数组就是 ...
- Poj 3259 Wormholes(spfa判负环)
Wormholes Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 42366 Accepted: 15560 传送门 Descr ...
- spfa判负环
bfs版spfa void spfa(){ queue<int> q; ;i<=n;i++) dis[i]=inf; q.push();dis[]=;vis[]=; while(!q ...
- poj 1364 King(线性差分约束+超级源点+spfa判负环)
King Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 14791 Accepted: 5226 Description ...
- 2018.09.24 bzoj1486: [HNOI2009]最小圈(01分数规划+spfa判负环)
传送门 答案只保留了6位小数WA了两次233. 这就是一个简单的01分数规划. 直接二分答案,根据图中有没有负环存在进行调整. 注意二分边界. 另外dfs版spfa判负环真心快很多. 代码: #inc ...
- BZOJ 4898 [APIO2017] 商旅 | SPFA判负环 分数规划
BZOJ 4898 [APIO2017] 商旅 | SPFA判负环 分数规划 更清真的题面链接:https://files.cnblogs.com/files/winmt/merchant%28zh_ ...
- [P1768]天路(分数规划+SPFA判负环)
题目描述 “那是一条神奇的天路诶~,把第一个神犇送上天堂~”,XDM先生唱着这首“亲切”的歌曲,一道猥琐题目的灵感在脑中出现了. 和C_SUNSHINE大神商量后,这道猥琐的题目终于出现在本次试题上了 ...
- LightOj 1221 - Travel Company(spfa判负环)
1221 - Travel Company PDF (English) Statistics problem=1221" style="color:rgb(79,107,114)& ...
- poj 2049(二分+spfa判负环)
poj 2049(二分+spfa判负环) 给你一堆字符串,若字符串x的后两个字符和y的前两个字符相连,那么x可向y连边.问字符串环的平均最小值是多少.1 ≤ n ≤ 100000,有多组数据. 首先根 ...
- BZOJ 1715: [Usaco2006 Dec]Wormholes 虫洞 DFS版SPFA判负环
Description John在他的农场中闲逛时发现了许多虫洞.虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前).John的每个农场有M条小路(无向边)连接着N ...
随机推荐
- 为做个程序员英语字典,我处理了StackOverflow和HackerNews10年5千万条数据
有点标题党,不过都说都真实的.英语技能对开发员人员至关重要.所有人都不喜欢背单词,但更惨的是背住的单词发现没怎么用,又慢慢地忘记了.本来计划给自己做个开发人员常用单词表,感觉可能对其它人也有用,所以就 ...
- 【GStreamer开发】GStreamer播放教程09——数字音频传输
目标 本教程展示GStreamer是如何进行数字音频传输的. 介绍 在常见的模拟格式外,高端的音频系统通常都接受数字格式,压缩的非压缩的都能接受.因为音频信号是从电脑传到音箱,用一种更有弹性的形态会更 ...
- ztree节点名称排序
// result 为后台返回的集合,在渲染tree前的数据 result = result.sort(function (a, b) { // 判断前面一个是字母,后面一个不是字母,那么不换位置,返 ...
- IdentityServer4 学习二
进入identityserver4的官网:https://identityserver.io/ 找到文档 从overview下开始按照官方文档练习: 安装自定义模板 dotnet new -i Ide ...
- ~request库的使用
官方文档: (中文)http://cn.python-requests.org/zh_CN/latest/ (英文)https://2.python-requests.org//en/master/a ...
- elasticsearch 开机自启
linux下开机自启: 在/etc/init.d目录下新建文件elasticsearch 并敲入shell脚本: #!/bin/sh #chkconfig: #description: elastic ...
- GoAccess 视图化access.log 日志
1.安装GoAccess 工具可以直接使用 apt-get install goaccess 2.使用goaccess命令将日志生成html文件 goaccess 日志路径 -o 输出HTML的路径 ...
- iOS - 反射机制: objc_property_t的使用
iOS属性反射:说白了,就是将两个对象的所有属性,用动态的方式取出来,并根据属性名,自动绑值.(注意:对象的类,如果是派生类,就得靠其他方式来实现了,因为得到不该基类的属性.) 常用的反射方式,有如下 ...
- 后端参数校验器v1.0(调用一个方法校验所有参数并得到校验结果,且包括错误原因)
一:介绍 在写后端时,面对多个参数,比如手机号码.密码等我们常常需要写验证逻辑,当需要验证的参数较多的时候我们会需要写很多的判断语句,这就造成了大量的代码冗余.因此我开发了一套参数验证器,只需要调用参 ...
- ReactNative使用 react-navigation 详解
react-navigation是官方主推的导航组件,致力于解决导航卡顿,数据传递,Tabbar和navigator布局,支持redux. 最新版本为3.x,大多文档介绍的是 1.x 或 2.x 的用 ...