spfa判断负环.java 3.2 KB
Newer Older
qq_36480062's avatar
c  
qq_36480062 已提交
1 2 3
package graph;

import java.util.ArrayDeque;
qq_36480062's avatar
c  
qq_36480062 已提交
4
import java.util.Arrays;
qq_36480062's avatar
c  
qq_36480062 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
import java.util.Scanner;

/**
 * 给定一个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
 * 分析:
 * 在Bellman-Ford算法中,我们知道,经过最大n-1轮松弛操作,
 * 从起点到所有点的最短距离就被确定下了。而图中若存在负权回路,
 * 则每次通过该负权回路来松弛距离时,最短距离都会减小,
 * 是不存在最短路径的。所以可以在spfa算法中用cnt数组存储当前点最短路径经过的边数,
 * 一旦经过了n条边,则说明经过了n + 1个点,
 * 而图中仅有n个点,该最短路径经过了一个点两次,所以必然存在负权回路。
 */
public class spfa判断负环 {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        int x, y, z;
        for (int i = 0; i < m; i++) {
            x = sc.nextInt();
            y = sc.nextInt();
            z = sc.nextInt();
            add(x, y, z);
        }
        if (spfa()) System.out.println("YES");
        else System.out.println("NO");
qq_36480062's avatar
c  
qq_36480062 已提交
49
        System.out.println(Arrays.toString(dis));
qq_36480062's avatar
c  
qq_36480062 已提交
50 51 52 53 54
    }

    static boolean spfa() {
        // 不需要初始化dist数组
        // 原理:如果某条最短路径上有n个点(除了自己),那么加上自己之后一共有n+1个点,由抽屉原理一定有两个点相同,所以存在环。
qq_36480062's avatar
c  
qq_36480062 已提交
55
        ArrayDeque<Integer> q = new ArrayDeque<Integer>();
qq_36480062's avatar
c  
qq_36480062 已提交
56
        for (int i = 1; i <= n; i++) {
qq_36480062's avatar
c  
qq_36480062 已提交
57 58
            q.add(i);//假设超级源点连接每个点权值都为0
            st[i] = true;
qq_36480062's avatar
c  
qq_36480062 已提交
59
        }
qq_36480062's avatar
c  
qq_36480062 已提交
60
        int t = 0, x;
qq_36480062's avatar
c  
qq_36480062 已提交
61 62
        while (!q.isEmpty()) {
            x = q.poll();
qq_36480062's avatar
c  
qq_36480062 已提交
63
            st[x] = false;
qq_36480062's avatar
c  
qq_36480062 已提交
64 65
            for (int i = he[x]; i != 0; i = ne[i]) {
                t = e[i];
qq_36480062's avatar
c  
qq_36480062 已提交
66
                if (dis[t] > dis[x] + w[i]) {
qq_36480062's avatar
c  
qq_36480062 已提交
67
                    count[t] = count[x] + 1;
qq_36480062's avatar
c  
qq_36480062 已提交
68
                    dis[t] = dis[x] + w[i];
qq_36480062's avatar
c  
qq_36480062 已提交
69
                    if (count[t] >= n) return true;
qq_36480062's avatar
c  
qq_36480062 已提交
70 71 72
                    if (!st[t]) {
                        q.add(t);
                        st[t] = true;
qq_36480062's avatar
c  
qq_36480062 已提交
73 74 75 76 77 78 79 80 81
                    }
                }
            }
        }
        return false;
    }

    static int[] count = new int[100005];
    static int[] dis = new int[100005];
qq_36480062's avatar
c  
qq_36480062 已提交
82
    static boolean[] st = new boolean[100005];
qq_36480062's avatar
c  
qq_36480062 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95 96
    static int[] he = new int[100005];
    static int[] w = new int[200005];
    static int[] ne = new int[200005];
    static int[] e = new int[200005];

    static void add(int a, int b, int c) {
        e[cnt] = b;
        w[cnt] = c;
        ne[cnt] = he[a];
        he[a] = cnt++;
    }

    static int n, m, cnt = 1;
}