洛谷P3385 【模板】负环(DFS求环)

洛谷题目传送门

HNOI爆零前回刷模板题

非常不正经的题目,目前并没有合适的优秀算法,就算是大家公认的dfs(还是不要强行叫dfs-spfa吧,概念应该不一样,这就是暴力dfs松弛答案)

但是对于随机数据来说,dfs有着优秀的效率,可以快速发现负环并退出

从每个点开始暴力dfs,记一个bool数组ins表示每个点是否在搜索栈中。如果发现可以松弛并且踏进了已经在栈中的点就说明找到了负环。

注意几点:

  1. YE5和N0 2333

  2. dis初始化为0,因为只要判负环,正权一开始并不用松弛

  3. 因为并没有说图连通,所以每个点都要作为起点跑一遍dfs

  4. 每个点都跑一遍有点麻烦,可以加一个剪枝,标记已经访问过的点,如果这个点之前已经松弛过了就不用再跑dfs了,反正也松弛不了。当然实际优化效果不是很理想,因为这个数组每次都要清空。。。。。。

#include<cstdio>
#include<cstring>
#define RG register
#define R RG int
#define gc if(++pi==iend)fread(pi=ibuf,1,SZ,stdin)
#define add(X,Y,V) v[++p]=V,to[p]=Y,ne[p]=he[X],he[X]=p
const int SZ=1<<20,N=200009,M=N<<1;
char ibuf[SZ],*iend=ibuf+SZ,*pi=iend-1;
int he[N],ne[M],to[M],v[M],d[N];
bool ins[N],vis[N];
inline int in(){
	gc;while(*pi<'-')gc;
	RG bool f=*pi=='-';if(f)gc;
	R x=*pi&15;gc;
	while(*pi>'-'){x*=10;x+=*pi&15;gc;}
	return f?-x:x;
}
bool dfs(R x){
	vis[x]=ins[x]=1;
	for(R y,i=he[x];i;i=ne[i])
		if(d[y=to[i]]>d[x]+v[i]){
			d[y]=d[x]+v[i];//松弛
			if(ins[y]||dfs(y))return !(ins[x]=0);//退回来记得把ins变成0
		}
	return ins[x]=0;
}
int main(){
	R T=in(),n,m,p,a,b,w,i;
	while(T--){
		n=in();m=in();p=0;
		while(m--){
			a=in();b=in();w=in();
			add(a,b,w);
			if(w>=0)add(b,a,w);
		}
		for(i=1;i<=n;++i)
			if(!vis[i]&&dfs(i)){
				puts("YE5");
				goto E;
			}
		puts("N0");
	  E:memset(he,0,(n+1)<<2);//都要清空
		memset(d,0,(n+1)<<2);
		memset(vis,0,n+1);
	}
	return 0;
}
posted @ 2018-04-13 21:50  Flash_Hu  阅读(267)  评论(0编辑  收藏  举报