负环

【题目描述】

判断是否存在负环。

【输入描述】

第一行输入一个正整数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| ≤ 200000,1 ≤ A,B ≤ N,T ≤ 10。

源代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Node
{
    int S,To,Next;
}Edge[400001];
int n,m,Num,i[200001],Head[200001];
bool Flag,In[200001];
void SPFA(int t) //DFS判负环,当然不能直接存在于SPFA中,但着实比BFS更快。
{
    In[t]=true;
    for (int a=Head[t];a;a=Edge[a].Next)
    {
        int T=Edge[a].To;
        if (i[T]>i[t]+Edge[a].S)
        {
            if (In[T]||Flag) //一般越往下越大,但如果再次处理并在队列中,那肯定是有环,且权值和为负。
            {
                Flag=true;
                break;
            }
            i[T]=i[t]+Edge[a].S;
            SPFA(T);
        }
    }
    In[t]=false;
}
void Add(int t1,int t2,int t)
{
    Edge[++Num].S=t;
    Edge[Num].To=t2;
    Edge[Num].Next=Head[t1];
    Head[t1]=Num;
}
void Solve()
{
    Num=Flag=0;
    memset(i,0x3f,sizeof(i));
    memset(Head,0,sizeof(Head));
    scanf("%d%d",&n,&m);
    for (int a=0;a<m;a++)
    {
        int t,t1,t2;
        scanf("%d%d%d",&t1,&t2,&t);
        Add(t1,t2,t);
        if (t>=0)
          Add(t2,t1,t);
    }
    for (int a=1;a<=n;a++) //可能不连通。
    {
        SPFA(a);
        if (Flag)
          break;
    }
    if (Flag) //小坑。
      puts("YE5");
    else
      puts("N0");
}
int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
      Solve();
    return 0;
}
原文地址:https://www.cnblogs.com/Ackermann/p/6062198.html