洛谷P3385 【模板】负环
题目描述
暴力枚举/SPFA/Bellman-ford/奇怪的贪心/超神搜索
寻找一个从顶点1所能到达的负环,负环定义为:一个边权之和为负的环。
输入输出格式
输入格式:
第一行一个正整数T表示数据组数,对于每组数据:
第一行两个正整数N M,表示图有N个顶点,M条边
接下来M行,每行三个整数a b w,表示a->b有一条权值为w的边(若w<0则为单向,否则双向)
输出格式:
共T行。对于每组数据,存在负环则输出一行"YE5"(不含引号),否则输出一行"N0"(不含引号)。
输入输出样例
说明
n≤2000
m≤3000
−10000≤w≤10000
T≤10建议复制输出格式中的字符串。 本题数据感谢@negiizhao的精心构造,请不要使用玄学算法 本题数据有更新
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<queue> 6 using namespace std; 7 long long read() 8 { 9 long long x=0,f=1; 10 char ch=getchar(); 11 while(ch>'9'||ch<'0') 12 { 13 if(ch=='-') 14 f=-1; 15 ch=getchar(); 16 } 17 while(ch>='0'&&ch<='9') 18 { 19 x=x*10+ch-'0'; 20 ch=getchar(); 21 } 22 return x*f; 23 } 24 const int maxn=20005; 25 const int maxm=100010; 26 int T,st=1,n,m,num; 27 bool flag; 28 bool vis[maxn]; 29 int dis[maxn],cnt[maxn],head[maxn],q[maxn]; 30 struct node 31 { 32 int v,w,nxt; 33 } e[maxm*2]; 34 void add(int x,int y,int z) 35 { 36 e[++num].v=y; 37 e[num].w=z; 38 e[num].nxt=head[x]; 39 head[x]=num; 40 } 41 bool spfa() 42 { 43 int l=0,r=0; 44 memset(dis,0x3f,sizeof(dis)); 45 memset(vis,0,sizeof(vis)); 46 memset(cnt,0,sizeof(cnt)); 47 memset(q,0,sizeof(q)); 48 vis[st]=1; 49 cnt[st]=1; 50 dis[st]=0; 51 q[r++]=st; 52 while(l!=r) 53 { 54 int u=q[l++]; 55 if(l>n) 56 l=0; 57 vis[u]=false; 58 for(int i=head[u]; i; i=e[i].nxt) 59 { 60 if(dis[e[i].v]>dis[u]+e[i].w) 61 { 62 dis[e[i].v]=dis[u]+e[i].w; 63 cnt[e[i].v]=cnt[u]+1; 64 if(cnt[e[i].v]>=n&&e[i].w<0) 65 return 1; 66 if(!vis[e[i].v]) 67 { 68 vis[e[i].v]=1; 69 if(dis[e[i].v]>dis[q[l]]) 70 { 71 l--; 72 if(l<0) 73 l=n; 74 q[l]=e[i].v; 75 } 76 else 77 { 78 q[r++]=e[i].v; 79 if(r>n) 80 r=0; 81 } 82 } 83 } 84 } 85 } 86 return false; 87 } 88 int main() 89 { 90 T=read(); 91 while(T--) 92 { 93 n=read(),m=read(); 94 memset(head,0,sizeof(head)); 95 num=0; 96 for(int i=1; i<=m; i++) 97 { 98 int x=read(),y=read(),w=read(); 99 add(x,y,w); 100 if(w>=0) 101 add(y,x,w); 102 } 103 if(spfa()) 104 printf("YE5\n"); 105 else 106 printf("N0\n"); 107 } 108 return 0; 109 }