负环
【题目描述】
判断是否存在负环。
【输入描述】
第一行输入一个正整数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; }