852. spfa判断负环 Java代码

32 篇文章 1 订阅
本文介绍了一种利用SPFA(Shortest Path First Algorithm,最短路径优先算法)来判断有向图中是否存在负环的算法。通过维护边数计数数组cnt,当节点间路径长度达到图中节点数量,可能存在环,重点寻找负环。通过构造超级源点并进行首次SPFA迭代,确保图连通性。
摘要由CSDN通过智能技术生成

输入样例:

3 3
1 2 -1
2 3 4
3 1 -4

输出样例:

Yes

算法思路:

用spfa判断负环,只需要在spfa求最短路的基础上维护一个cnt数组,cnt[i] = j:表示从源点到顶点i经过的边数是j。

存在负环的条件:cnt[x] >= n,意味着1~x经过了n条边,n+1个点,而图中只有n个点,所以n+1个点中至少有一个点出现了两次,即存在环,要想使得距离更小,环只能是负环。

为了确保图是连通图,不漏下任何一个负环,可以在最开始时构造一个超级源点p,因为点p是虚拟的,dis数组表示p到当前点的距离,初始时dis均为0,cnt数组也均为0,并执行第一次spfa的迭代,将所有图中的点入队。所以判断原图是否有环,就等价于判断新图是否有环。

Java代码:

import java.io.*;
import java.util.*;

public class Main {
	static int n, m;
	static final int N = 2005, M = 10005;
	static int []e = new int[M];
	static int []ne = new int[M];
	static int []w = new int[M];
	static int []h = new int[N];
	static int idx = 0;
	static int []dis = new int[N];
	static boolean []vis = new boolean[N];
	static int []cnt = new int[N];
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] split = br.readLine().split(" ");
		n = Integer.parseInt(split[0]);
		m = Integer.parseInt(split[1]);
		Arrays.fill(h, -1);
		
		for(int i = 0; i < m; i++) {
			split = br.readLine().split(" ");
			int a = Integer.parseInt(split[0]);
			int b = Integer.parseInt(split[1]);
			int c = Integer.parseInt(split[2]);
			add(a, b, c);
		}
		if(spfa()) System.out.println("Yes");
		else System.out.println("No");
	}
	
	public static boolean spfa() {
		Queue<Integer> qu = new LinkedList<>();
		for(int i = 1; i <= n; i++) { // 开始时将所有点都入队,防止图不是连通图
			qu.add(i);
			vis[i] = true;
		}
		
		while(!qu.isEmpty()) {
			int t = qu.poll();
			vis[t] = false;
			
			for(int i = h[t]; i != -1; i = ne[i]) {
				int j = e[i];
				if(dis[j] > dis[t] + w[i]) {
					dis[j] = dis[t] + w[i];
					cnt[j] = cnt[t] + 1;  // 在更新距离的同时更新边数
					
					if(cnt[j] >= n) return true;
					if(!vis[j]) {
						qu.add(j);
						vis[j] = true;
					}
				}
			}
		}
		return false;
	}
	
	public static void add(int a, int b, int c) {
		e[idx] = b;
		w[idx] = c;
		ne[idx] = h[a];
		h[a] = idx++;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值