为什么我的联合查找不交集集算法不能通过所有测试用例?

时间:2019-04-02 22:45:45

标签: java algorithm disjoint-sets union-find disjoint-union

样本输入:

1
3 2
1 2
2 3

第一行=测试用例数

第二行的第一人数=人数

第二行第二个数字=友谊数F

遵循F线=友谊

输出将是最大的朋友组的大小。

因此,该输入的样本输出为3。[[1、2、3])

我的解决方案:

import java.util.Scanner;
import java.util.HashMap;
import java.util.Collections;

public class Main {

    public static void main (String args[]) {
        Scanner reader = new Scanner(System.in);
        int tests = reader.nextInt();
        for (int i = 0; i < tests; i++) {
            int numcitizens = reader.nextInt();
            // the input is 1-indexed so I create the parent array as such
            int[] parent = new int[numcitizens + 1];
            for (int j = 0; j < (numcitizens + 1); j++) {
                parent[j] = j;
            }
            int[] rank = new int[numcitizens + 1];
            int numpairs = reader.nextInt();
            for (int j = 0; j < numpairs; j++) {
                int A = reader.nextInt();
                int B = reader.nextInt();
                union(A, B, parent, rank);
            }
            HashMap<Integer, Integer> histo = new HashMap<Integer, Integer>();
            for (int j = 1; j < parent.length; j++) {
                int root = parent[j];
                if (!histo.containsKey(root)) {
                    histo.put(root, 1);
                }
                else {
                    histo.put(root, histo.get(root) + 1);
                }

            }
            int max = Collections.max(histo.values());
            System.out.println(max);
        }
    }

    // UFDS find
    static int find(int x, int[] parent) {

        if (parent[x]!= x) {
            parent[x] = find(parent[x], parent);
        }

        return parent[x];
    }

    // UFDS union
    static void union(int x, int y, int[] parent, int[] rank) {
        int xRoot = find(x, parent);
        int yRoot = find(y, parent);

        if (xRoot == yRoot) {
            return;
        }
        else {
            if (rank[xRoot] < rank[yRoot]) {
                parent[xRoot] = yRoot;
            }

            else if (rank[yRoot] < rank[xRoot]) {
                parent[yRoot] = xRoot;
            }

            else {
                parent[yRoot] = xRoot;
                for (int i = 0; i < parent.length; i++) {
                    if (parent[i] == yRoot) {
                        parent[i] = xRoot;
                    }
                }
                rank[xRoot] = rank[xRoot] + 1;
            }
        }
    }
}

它适用于示例输入,但是当通过在线判断系统(通过数百个测试用例运行它)时,它会告诉我错误的输出。不知道我的错误可能在哪里?对我来说似乎是一个简单的UFDS问题。

3 个答案:

答案 0 :(得分:1)

您在union中放入的for循环会破坏性能。只是拿出来。

在直方图循环中,您需要int root = find(j,parent);

numcitizens为零时,您的代码将引发异常。

修复这些问题,您的代码将正常工作。

还有一些其他提示:

  • 我总是按大小合并,而不是按等级合并。它具有相同的复杂性,并且大小通常很有用。在这种情况下,您将不需要构建直方图,因为您将拥有每个根的大小。

  • 我为数据结构使用单个int[]数组。如果 v 的值> = 0,则它是具有该大小的根集(0表示该索引处没有集或空集)。否则,〜v 是指向父集的链接。我最近在此答案中使用了该结构:Algorithm: use union find to count number of islands

答案 1 :(得分:0)

每个人拥有的朋友数不是parent数组。每个人的排名 是由集合表示的树的高度,即该人拥有的朋友的数量。 因此请在for循环中使用root=rank[j]+1来计算最多的朋友。

int max=Integer.MAX_VALUE;
for(int r:rank){
    max=Math.max(max,r+1);
}
System.out.println(max);

答案 2 :(得分:-1)

您似乎正在执行与AVL Tree实现类似的操作。

在方法的最后“其他”情况下,尝试将“静态无效联合”中的两个if语句更改为此

        if (rank[xRoot] < rank[yRoot]) {
            parent[xRoot] = yRoot;
        }

        else if (rank[yRoot] > rank[xRoot]) {
            parent[yRoot] = xRoot;
        }
        else //this is a duplicate case in AVL tree terms

因此,您得到的代码应如下所示。

// UFDS union
static void union(int x, int y, int[] parent, int[] rank) {
    int xRoot = find(x, parent);
    int yRoot = find(y, parent);

    if (xRoot == yRoot) {
        return;
    }
    else {
        if (rank[xRoot] < rank[yRoot]) {
            parent[xRoot] = yRoot;
        }

        else if (rank[yRoot] > rank[xRoot]) {
            parent[yRoot] = xRoot;
        }

        else {
            parent[yRoot] = xRoot;
            for (int i = 0; i < parent.length; i++) {
                if (parent[i] == yRoot) {
                    parent[i] = xRoot;
                }
            }
            rank[xRoot] = rank[xRoot] + 1;
        }
    }
}