AcWing852- spfa判断负环
题目描述
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数。
请你判断图中是否存在负权回路。
输入格式
第一行包含整数 n 和 m。
接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x到点 y 的有向边,边长为 z。
输出格式
如果图中存在负权回路,则输出 Yes
,否则输出 No
。
数据范围
1≤n≤2000,
1≤m≤10000,
图中涉及边长绝对值均不超过 10000。
输入样例:
3 3
1 2 -1
2 3 4
3 1 -4
输出样例:
Yes
题解
package acWing852;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
public class Main {
static int max = 0x3f3f3f3f;
static int N = 2010, M = 10010;
static int n,m;
static int h[] = new int[N],e[] = new int[M],ne[] = new int[M],w[] = new int[M],idx;
static int dist[] = new int[N],cnt[] = new int[N];
static Boolean[] st = new Boolean[N];
static void add(int a, int b,int c) {
e[idx] = b;w[idx] = c;ne[idx] = h[a];h[a] = idx++;
}
static String spfa() {
Queue<Integer> q = new LinkedList<>();
for(int i=1;i<=n;i++) {
st[i] = true;
q.add(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];
if(dist[j]>dist[t]+w[i] ){
dist[j] = dist[t] +w[i];
cnt[j] = cnt[t] +1;
if(cnt[j]>=n) {
return "Yes";
}
if(!st[j]) {
q.add(j);
st[j] = true;
}
}
}
}
return "No";
}
public static void main(String[] args) throws IOException {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String str[] = bf.readLine().split(" ");
n = Integer.parseInt(str[0]);m = Integer.parseInt(str[1]);
Arrays.fill(h, -1);
Arrays.fill(dist, max);
Arrays.fill(st, false);
for(int i=0;i<m;i++) {
str = bf.readLine().split(" ");
int a = Integer.parseInt(str[0]),b = Integer.parseInt(str[1]),c = Integer.parseInt(str[2]);
add(a,b,c);
}
System.out.println(spfa());
}
}