SPFA - Luogu 3385 【模板】负环

【模板】负环

描述

找负环

输入

第一行一个正整数T表示数据组数,对于每组数据:
第一行两个正整数N M,表示图有N个顶点,M条边
接下来M行,每行三个整数a b w,表示a->b有一条权值为w的边(若w<0则为单向,否则双向)

输出

共T行。对于每组数据,存在负环则输出一行"YE5"(不含引号),否则输出一行"N0"(不含引号)。

样例

输入
2
3 4
1 2 2
1 3 4
2 3 1
3 1 -3
3 3
1 2 3
2 3 4
3 1 -8
输出
N0
YE5

提示

N,M,|w|≤200 000;1≤a,b≤N;T≤10 建议复制输出格式中的字符串。
此题普通Bellman-Ford或BFS-SPFA会TLE


此题普通Bellman-Ford或BFS-SPFA真的会TLE!证明: https://www.luogu.org/record/show?rid=3554669

判断负环最常用的就是spfa。当然各位大佬搜索暴力也能过的……
而判负环的spfa也有2种,一种是BFS,而另一种是DFS怎么都是大法师

BFS

BFS的尤其简单
在普通的spfa上加一个数组,记录各个点被更新/入栈的次数,一旦大于了某个数(一般取点数)就判定是有负环的。
BFS_SPFA的期望时间复杂度是\(O(\)边数\(*\)所有顶点进队的平均次数\()\),
既然存在负环,这个期望的时间复杂度就真的是期望了,鬼知道这负环有多长,还要绕多少圈,慢的一比。

DFS

而DFS的要改一改
找负环,就是找一条权值和为负的回路,
而在我们的DFS过程中,根据SPFA,我们找到的负环一定包含当前枚举的这个点。
即相当于我们找了一圈回来,发现现在的权值比原来的要小,那么我们就一定走了一个负环。
那么我们就分别枚举所有的点作为起点找负环,为了不TLE,如果已经找到一个负环就不再继续枚举。
代码蒯上

#include<iostream>
#include<iomanip>
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gotcha()
{
    register int _a=0;bool _b=1;register char _c=getchar();
    while(_c<'0' || _c>'9'){if(_c=='-')_b=0;_c=getchar();}
    while(_c>='0' && _c<='9')_a=_a*10+_c-48,_c=getchar();
    return _b?_a:-_a;
}
const int _ = 200002;
struct edge{int to,ne,len;edge(){to=ne=len=0;}}e[_<<1];
int he[_]={0},ecnt=0;
void add(int fr,int to,int len)
{e[++ecnt].to=to,e[ecnt].len=len,e[ecnt].ne=he[fr],he[fr]=ecnt;}
int n,m,dis[_];
bool ed[_]={0},vict;
void spfa(int d)
{
    register int i,b;
    if(vict)return;
    ed[d]=1;
    for(i=he[d];i;i=e[i].ne)
    {
        b=e[i].to;
        if(dis[d]+e[i].len<dis[b])
        {dis[b]=dis[d]+e[i].len;if(ed[b]){vict=1;return;}spfa(b);}
    }
    ed[d]=0;
    return;
}
int main()
{
    register int i,k,a,b,t=gotcha();
    while(t--)
    {
        n=gotcha(),m=gotcha();
        memset(he,0,4*n+8),memset(ed,0,n+2),memset(dis,63,4*n+8),ecnt=0,vict=0;
        for(i=1;i<=m;i++)
        {
            a=gotcha(),b=gotcha(),k=gotcha();
            add(a,b,k);if(k>=0)add(b,a,k);
        }
        for(i=1;i<=n;i++){spfa(i);if(vict)break;}
        if(vict)puts("YE5");
        else puts("N0");
    }
    return 0;
}
posted @ 2017-10-03 16:26  iot;  阅读(281)  评论(0编辑  收藏  举报
知识共享许可协议
年轻人,你需要更多的知识