zoukankan      html  css  js  c++  java
  • SPFA判断负环BFS+DFS

    SPFA判断负环
    https://blog.csdn.net/forever_dreams/article/details/81161527
    【bfs版】
    首先我们要知道,对于一个不存在负环的图,从起点到任意一个点最短距离经过的点最多只有 n 个
    这样的话,我们用 cnt[ i ] 表示从起点(假设就是 1)到 i 的最短距离包含点的个数,初始化 cnt[ 1 ] = 1,
    那么当我们能够用点 u 松弛点 v 时,松弛时同时更新 cnt[ v ] = cnt[ u ] + 1,若发现此时 cnt[ v ] > n,那么就存在负环
    还有一种方法是记录每个点的入队次数,入队次数大于 n 就说明有负环,但是这样做一般都要比上面的方法慢。举个例子,在一个由 n 个点构成的负环中,这个方法要绕环 n 次,
    而上面的方法绕环 1 次就行了
    代码(Yes 是存在负环,No 是不存在负环,图是联通的)

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<stack>
    #include<cstdio>
    #include<queue>
    #include<map>
    #include<vector>
    #include<set>
    using namespace std;
    const int maxn=10100;
    const int maxm=20050;
    const int INF=0x3fffffff;
    typedef long long LL;
    typedef unsigned long long ull;
    /*
    SPFA判断负环 
    https://blog.csdn.net/forever_dreams/article/details/81161527
    【bfs版】
    首先我们要知道,对于一个不存在负环的图,从起点到任意一个点最短距离经过的点最多只有 n 个
    这样的话,我们用 cnt[ i ] 表示从起点(假设就是 1)到 i 的最短距离包含点的个数,初始化 cnt[ 1 ] = 1,
    那么当我们能够用点 u 松弛点 v 时,松弛时同时更新 cnt[ v ] = cnt[ u ] + 1,若发现此时 cnt[ v ] > n,那么就存在负环
    还有一种方法是记录每个点的入队次数,入队次数大于 n 就说明有负环,但是这样做一般都要比上面的方法慢。举个例子,在一个由 n 个点构成的负环中,这个方法要绕环 n 次,
    而上面的方法绕环 1 次就行了
    代码(Yes 是存在负环,No 是不存在负环,图是联通的)
    */ 
    int head[maxn],to[maxm],nex[maxm],wei[maxm];
    int num,n,m;
    int vis[maxn],dis[maxn],cnt[maxn];
    bool flag;
    void adde(int x,int y,int z){
    	to[++num]=y;
    	nex[num]=head[x];
    	wei[num]=z;
    	head[x]=num;
    }
    bool spfa(int s){
    	memset(dis,0x3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	dis[s]=0;
    	queue<int> q;
    	q.push(s);
    	vis[s]=1;
    	cnt[s]=1;
    	while(!q.empty()){
    		int x=q.front();
    		q.pop();
    		vis[x]=0;
    		for(int i=head[x];i;i=nex[i]){
    			int t=to[i];
    			if(dis[t]>dis[x]+wei[i]){
    				dis[t]=dis[x]+wei[i];
    				cnt[t]=cnt[x]+1;
    				if(cnt[t]>n) return false;
    				if(!vis[t]) {
    					q.push(t);
    					vis[t]=1;
    				} 
    			}
    		}
    	}
    	return true;
    }
    int main(){
    	scanf("%d %d",&n,&m);
    	int x,y,z;
    	for(int i=1;i<=m;i++){
    		scanf("%d %d %d",&x,&y,&z);
    		adde(x,y,z);
    	}
    	flag=spfa(1);
    	if(flag) cout<<"YES"<<endl;
    	else cout<<"NO"<<endl;
    	
    return 0;
    }
    

      

    【dfs版】
    基于 dfs 版的 SPFA 相当于是把"先进先出"的队列换成了"先进后出"的栈
    也就是说,每次都以刚刚松弛过的点来松弛其他的点,如果能够松弛点 x 并且 x 还在栈中,那图中就有负环
    一般来说的话,若存在负环,那么 dfs 会比 bfs 快
    但是如果不存在负环,dfs 可能会严重影响求最短路的效率,要谨慎使用

    void spfa(int x){
    	vis[x]=1;
    	for(int i=head[x];i;i=nex[i]){
    		int t=to[i];
    		if(dis[t]>dis[x]+wei[i]){
    			if(vis[t]) {
    				flag=false;
    				return;
    			}
    			dis[t]=dis[x]+wei[i];
    			spfa(t);
    		}
    	}
    	vis[x]=false; //要回溯 
    }
    
    int main(){
    	memset(dis,0x3f,sizeof(dis));
    	d[1]=0;
    	spfa(1);
    } 
    

      

  • 相关阅读:
    外部晶振的使用原因与内部RC振荡器的使用方法
    Linux系统下ifconfig命令使用及结果分析
    浅谈程序的内存布局
    物理内存与虚拟内存之间的映射
    如何正确理解套接字
    研究自动驾驶技术的算法需要哪些知识?
    如何防止头文件被重复包含或引用?
    虚拟机-VMware小结-汇总
    局域网内快速传输数据
    thingsboard安装
  • 原文地址:https://www.cnblogs.com/shirlybaby/p/13458483.html
Copyright © 2011-2022 走看看