【定义与概念】

给定一张有向图,若其中存在一个环的所有权值之和为负数,这个环称为负环。

【算法实现】

当然,负环的求解可以暴搜,但是时间复杂度就难以入眼了,我们回到求解单源最短路径算法上面,看看它们能否求解。

我们知道

各种最短路算法
算法名称 能否处理负边 时间复杂度
Dijkstra 不能,负权的存在使得最短路径不一定最短 O(n^2)
堆优化Dijkstra 不能,如上 O(mlogn)
Bellman-Ford O(nm)
SPFA O(km)

我们主要使用SPFA,讲一下SPFA判断负环。

SPFA有三种以上的方法判断负环:

  1. 设cnt[x]表示1~x的最短路径包含边数,cnt[1]=0。当收敛边权(判断三角形不等式)时,更新cnt[y]=cnt[x]+1。如果某时cnt[x]>=边的总数m,说明存在负环。
  2. 记录每个点入队的次数,如果某个点入队次数超过点的总数n,说明存在最小环。
  3. 卡时判负环,判负环最骚的操作。给队列总长度做限制,超过限制说明有环。至于这个限制具体是什么,请去问玄学,我不知道。

给出第一、二种解法的参考吧。

拿道板子题出来。

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判负环的更多相关文章

  1. POJ 3259 Wormholes(SPFA判负环)

    题目链接:http://poj.org/problem?id=3259 题目大意是给你n个点,m条双向边,w条负权单向边.问你是否有负环(虫洞). 这个就是spfa判负环的模版题,中间的cnt数组就是 ...

  2. Poj 3259 Wormholes(spfa判负环)

    Wormholes Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 42366 Accepted: 15560 传送门 Descr ...

  3. spfa判负环

    bfs版spfa void spfa(){ queue<int> q; ;i<=n;i++) dis[i]=inf; q.push();dis[]=;vis[]=; while(!q ...

  4. poj 1364 King(线性差分约束+超级源点+spfa判负环)

    King Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 14791   Accepted: 5226 Description ...

  5. 2018.09.24 bzoj1486: [HNOI2009]最小圈(01分数规划+spfa判负环)

    传送门 答案只保留了6位小数WA了两次233. 这就是一个简单的01分数规划. 直接二分答案,根据图中有没有负环存在进行调整. 注意二分边界. 另外dfs版spfa判负环真心快很多. 代码: #inc ...

  6. BZOJ 4898 [APIO2017] 商旅 | SPFA判负环 分数规划

    BZOJ 4898 [APIO2017] 商旅 | SPFA判负环 分数规划 更清真的题面链接:https://files.cnblogs.com/files/winmt/merchant%28zh_ ...

  7. [P1768]天路(分数规划+SPFA判负环)

    题目描述 “那是一条神奇的天路诶~,把第一个神犇送上天堂~”,XDM先生唱着这首“亲切”的歌曲,一道猥琐题目的灵感在脑中出现了. 和C_SUNSHINE大神商量后,这道猥琐的题目终于出现在本次试题上了 ...

  8. LightOj 1221 - Travel Company(spfa判负环)

    1221 - Travel Company PDF (English) Statistics problem=1221" style="color:rgb(79,107,114)& ...

  9. poj 2049(二分+spfa判负环)

    poj 2049(二分+spfa判负环) 给你一堆字符串,若字符串x的后两个字符和y的前两个字符相连,那么x可向y连边.问字符串环的平均最小值是多少.1 ≤ n ≤ 100000,有多组数据. 首先根 ...

  10. BZOJ 1715: [Usaco2006 Dec]Wormholes 虫洞 DFS版SPFA判负环

    Description John在他的农场中闲逛时发现了许多虫洞.虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前).John的每个农场有M条小路(无向边)连接着N ...

随机推荐

  1. Keystone

    Kenstone各个概念的比喻: User 住宾馆的人 Credentials 开启房间的钥匙 Authentication 宾馆为了拒绝不必要的人进出宾馆,专门设置的机制,只有拥有钥匙的人才能进出 ...

  2. todo---java中的json探讨

    1.json的命名格式 2.json赋值原则 3.json常用的工具 4.json的处理的第三方软件比较 5.json的起源 6.关于json串的对于null ,"" 的不同的第三 ...

  3. Python19之函数和过程

    一.函数和过程 函数和过程都是指一段实现特定功能的代码段,如果该代码段有返回值则称为函数,否则称为过程. 注:Python中只有函数而没有过程,就算是函数体内没有return语句返回一个值,Pytho ...

  4. Python进阶: Decorator 装饰器你太美

    函数 -> 装饰器 函数的4个核心概念 1.函数可以赋与变量 def func(message): print('Got a message: {}'.format(message)) send ...

  5. python检测当前端口是否使用

    基于python检测端口是否在使用 - 缘起花渊 - 博客园https://www.cnblogs.com/yqmcu/p/9804002.html def net_is_used(port,ip=' ...

  6. Kubernetes(k8s) docker 修改 /dev/shm大小

    一.问题 /dev/shm在/etc/fstab中挂载,对应tmpfs,实际使用的是内存的空间.默认情况下,/dev/shm为物理内存大小的一半. 在Kubernetes上跑docker,发现/dev ...

  7. Qt界面阴影效果(背景图片)

    实现原理: 1.顶层窗体设置为无边框,背景半透明 2.顶层窗体的子窗体使用带有阴影的图片做背景 代码: //CMainWindow.h#ifndef CMAINWINDOW_H#define CMAI ...

  8. c#使用GDI进行简单的绘图

    https://www.2cto.com/database/201805/749421.html https://zhidao.baidu.com/question/107832895.html pr ...

  9. mongodb入门基本语法

    show dbs 查看所有数据库列表 二. 创建数据库 使用数据库. 创建数据库 use student 如果真的想把这个数据库创建成功, 那么必须插入一个数据. 数据库中不能直接插入数据,只能往集合 ...

  10. git bash push 本地的commit到远程 -- ssh keys设置

    1.  检查是否已经创建 ssh keys git bash 下,cd ~/.ssh 如何出现“No such file or directory”,则表示需要创建一个ssh keys. 2. 创建新 ...