Luogu P3385 【模板】负环
题目描述
暴力枚举/SPFA/Bellman-ford/奇怪的贪心/超神搜索
输入输出格式
输入格式:
第一行一个正整数T表示数据组数,对于每组数据:
第一行两个正整数N M,表示图有N个顶点,M条边
接下来M行,每行三个整数a b w,表示a->b有一条权值为w的边(若w<0则为单向,否则双向)
输出格式:
共T行。对于每组数据,存在负环则输出一行"YE5"(不含引号),否则输出一行"N0"(不含引号)。
输入输出样例
说明
N,M,|w|≤200 000;1≤a,b≤N;T≤10 建议复制输出格式中的字符串。
此题普通Bellman-Ford或BFS-SPFA会TLE
DFS版SPFA判负环,注意输出有坑点,输出YE5 和 N0 而不是 YES 和 NO
1 //2018年3月4日22:19:48 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 const int N = 400001; 9 const int M = 400001; 10 11 struct Edge{ 12 int len, to, nxt; 13 }E[M]; 14 int fir[N], edge_num; 15 16 void addEdge(int x, int y, int z){ 17 E[++edge_num].to = y; 18 E[edge_num].len = z; 19 E[edge_num].nxt = fir[x]; 20 fir[x] = edge_num; 21 } 22 23 int T, n, m; 24 int dis[N], vis[N], flag; 25 void spfa(int A){ 26 vis[A] = 1; 27 for(int i=fir[A]; i; i=E[i].nxt){ 28 if(dis[E[i].to] > dis[A] + E[i].len){ 29 if(vis[E[i].to] || flag){ flag = 1; break; } 30 dis[E[i].to] = dis[A] + E[i].len; 31 spfa(E[i].to); 32 } 33 } 34 vis[A] = 0; 35 } 36 37 int main(){ 38 scanf("%d", &T); 39 while(T--){ 40 flag = 0; 41 memset(E, 0, sizeof(E)); edge_num = 0; memset(fir, 0, sizeof(fir)); 42 scanf("%d%d", &n, &m); 43 for(int i=1; i<=m; i++){ 44 int x, y, z; 45 scanf("%d%d%d", &x, &y, &z); 46 if(z >= 0){ 47 addEdge(x, y, z); addEdge(y, x, z); 48 }else addEdge(x, y, z); 49 } 50 for(int i=1; i<=n; i++){ 51 spfa(i); if(flag) break; 52 } 53 if(flag) puts("YE5"); 54 else puts("N0"); 55 } 56 57 return 0; 58 }