• 负环详解


    什么是负环?

    顾名思义,就是一个所有边的边权和为负数的环

    出现负环会怎么样?

    我们知道,一般情况下,图上的最短路都是确定的。但是一旦图上有一个负环,(s)(t)的最短路就会不远千里的去覆盖上这个环(只要能够到达),并且不厌其烦的走上一遍又一遍。由于负环的边权和是负的,并且它是一个环,也就是说走一遍和走无数遍都停留在进入的那个点。那么最短路每经过一次这个负环,这个费用都会缩小一点,如果经过了无数次,也就是无穷小,也就是不存在最短路。当然这里有一个限定,就是每个点经过的次数不能超过(1)次。

    既然负环的影响这么大,那么就要引出我们的下一个问题了。

    怎么判定负环?

    相信大家都学过至少两种最短路的计算方法,而且一定也都会(dijkstra)(SPFA)这两种算法(如果不会的请先去学习SPFA再来观看此博客)。花开两朵,各表一枝。我们这里只谈(SPFA)。大家都知道,(SPFA)的判定方式就是不断地收紧每个点到起点的最短路径,每次都不一定会收到最紧,但只要有解,最终一定会收成最紧(这也正是它这么好卡的原因,一点一点的,能不慢吗)。我们前面提到过,如果存在负环,那么最短路会不断缩小至无穷小。那么这里我们就可以应用它的这一特点。在(SPFA)中,每个点最短被其他(n-1)个点各收紧一次,如果被收紧了(n)次,显然是不合理的。那么我们就记录每个点被收紧的次数,有任何点超过(n)次,就可以判定存在负环了,如果(SPFA)成功运行完了,就证明不存在负环。

    奇妙的是,我使用单调队列优化(SPFA)没有过这道题,所以大家还是用普通的(SPFA)来判定吧(毕竟出题人总不可能让你没法判定)。

    题目链接

    下面是代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cctype>
    #include<queue>
    #define ll long long
    #define gc getchar
    #define maxn 2050
    #define maxm 3050
    using namespace std;
    
    inline ll read(){
    	ll a=0;;int f=0;char p=gc();
    	while(!isdigit(p)){f|=p=='-';p=gc();}
    	while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
    	return f?-a:a;
    }int t,n,m;
    
    struct ahaha{
    	int w,to,next;
    }e[maxm<<1];int tot,head[maxn];
    inline void add(int u,int v,int w){
    	e[tot]={w,v,head[u]};head[u]=tot++;
    }
    
    queue<int>q;
    int d[maxn],s[maxn];
    inline bool spfa(){d[1]=0;
    	q.push(1);
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=head[u];~i;i=e[i].next){
    			int v=e[i].to;if(d[v]<=d[u]+e[i].w)continue;
    			if(s[v]+1==n)return 1;++s[v];d[v]=d[u]+e[i].w;
    			q.push(v);
    		}
    	}return 0;
    }
    
    inline void clear(){tot=0;
    	memset(head,-1,sizeof head);
    	memset(d,63,sizeof d);
    	memset(s,0,sizeof s);
    }
    
    int main(){
    	t=read();
    	while(t--){clear();
    		n=read();m=read();
    		for(int i=1;i<=m;++i){
    			int u=read(),v=read(),w=read();
    			add(u,v,w);if(w>=0)add(v,u,w);
    		}
    		puts(spfa()?"YE5":"N0");
    		while(!q.empty())q.pop();
    	}
    	return 0;
    }
    

    很久没有接触过OI了,有些生疏,也就不放例题了(其实是没时间找了)。

    不知我的博客是否对你有帮助呢?如果对你有些许帮助,不妨点个推荐吧。

  • 相关阅读:
    看过的代码
    ScipyLectures-simple学习笔记
    机器学习1一个月2017/11/24-2017/12/24
    机器学习课程 matlab 练习
    win7 win8 快捷键直接调出任务管理器
    java 关于getProperty()方法中反斜杠问题
    把myeclipse中html/jsp文件的视图调到只看代码
    Win7 server2008 共享文件夹 不输入网络密码
    别用visual editor了,用WindowBuilder
    visual editor ve1.5下载
  • 原文地址:https://www.cnblogs.com/hanruyun/p/11361632.html
Copyright © 2020-2023  润新知