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

洛谷题目传送门

HNOI爆零前回刷模板题

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

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

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

注意几点:

  1. YE5和N0 2333

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

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

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

#include
#include
#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;
}

转载于:https://www.cnblogs.com/flashhu/p/8824202.html

你可能感兴趣的:(洛谷P3385 【模板】负环(DFS求环))