AcWing----852. spfa判断负环 (Java)_spfa算法判断负环_利用最短路的长度

原题链接

①. 题目

在这里插入图片描述

②. 思路

  • 负环:环路之和为负, 求最短路的时候会不断在负环路打转。
  • 需要从每个点都出发一次,才能完全确定此图中是否有环
  • 求负环的常用方法,基于spfa,一般都用方法 2
1:统计每个点入队的次数,如果某个点入队n次,则说明存在负环
2:统计当前每个点的最短路中所包含的边数,如果某点的最短路所包含的边数大于等于n,则也说明存在环

spfa判断步骤

1、dist[x] 记录虚拟源点到x的最短距离

2、cnt[x] 记录当前x点到虚拟源点最短路的边数,初始每个点到虚拟源点的距离为0,只要他能再走n步,即cnt[x] >= n,则表示该图中一定存在负环,由于从虚拟源点到x至少经过n条边时,则说明图中至少有n + 1个点,表示一定有点是重复使用

3、若dist[j] > dist[t] + w[i],则表示从t点走到j点能够让权值变少,因此进行对该点j进行更新,并且对应cnt[j] = cnt[t] + 1,往前走一步

4、该题是判断是否存在负环,并非判断是否存在从1开始的负环,因此需要将所有的点都加入队列中,更新周围的点

③. 学习点

④. 代码实现

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
    
    
	/*
	 * 统计当前每个点的最短路中所包含的边数,如果某点的最短路所包含的边数大于等于n,则也说明存在环
	 */
	static int N=10010;
	static int[] ne=new int[N],e=new int[N],h=new int[N],w=new int[N];
	static int idx,n,m;
	static boolean[] st=new boolean[N];// st[i] 要来表示节点i是否在队列里面
	static int[] cnt=new int[N];  //记录虚拟源点到x的最短距离
	static int[] dist=new int[N]; //记录当前x点到虚拟源点最短路的边数
	public static void main(String[] args) {
    
    
		Scanner sc = new Scanner(System.in);
		n=sc.nextInt();m=sc.nextInt();
		
		Arrays.fill(h,-1);
		for (int i = 1; i<=m; i++) {
    
    
			int a=sc.nextInt(),b=sc.nextInt(),c=sc.nextInt();
			add(a,b,c);
		}
		if(spfa()) {
    
    
			System.out.println("Yes");
		}else{
    
    
			System.out.println("No");
		}
	}
	
	static void add(int a,int b,int c) {
    
    
		e[idx]=b;
		w[idx]=c;
		ne[idx]=h[a];
		h[a]=idx++;
	}
	
	static boolean spfa() {
    
    
		//负环不一定是从1点开始 ,将所有的点入队列
		Queue<Integer> q=new LinkedList<>();
		for (int i = 1; i <=n; i++) {
    
    
			q.offer(i);
		}
		while(!q.isEmpty()) {
    
    
			int t=q.poll();
			st[t]=false;
			for(int i=h[t];i!=-1;i=ne[i]) {
    
    
				int j=e[i];
				//表示从t点走到j点能够让权值变少,因此进行对该点j进行更新
				if(dist[j]>dist[t]+w[i]) {
    
    
					dist[j]=dist[t]+w[i];
					cnt[j]=cnt[t]+1; //往前走一步
					//若有n条边,至少有n+1个节点
					if(cnt[j]>=n) {
    
    
						return true;
					}
					if(!st[j]) {
    
    
						st[j]=true;
						q.offer(j);
					}
				}
			
			}
		}
	return false;
	}
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45480785/article/details/114106740