Почему мой алгоритм Union Find Disjoint Sets для этой задачи не проходит все тесты?

Пример ввода:

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.

Попробуйте ввести 1, 4 3, 1 2, 3 4, 4 1. Результатом должно быть то, что цепочка друзей 3-4-1-2 имеет размер 4, но ваш код печатает 3.

Andreas 03.04.2019 00:54

@Andreas Андреас, я обновил код самой последней функции else, чтобы исправить это; все еще говорит мне неправильный ответ

J. Doe 03.04.2019 01:11
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
540
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Количество друзей у каждого человека не равно parentмассиву. Ранг каждого человека - это высота дерева, представленная набором, т.е. количество друзей, которые есть у этого человека. поэтому используйте root=rank[j]+1 в цикле for для подсчета максимального количества друзей.

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

Ранг - это высота. Я не пытаюсь получить наибольшую глубину, я пытаюсь получить наибольшее количество узлов

J. Doe 03.04.2019 01:37

В этом случае высота также является количеством узлов

vijay 03.04.2019 01:40

Как? Дерево типа 3-4-1-2 без сжатия пути имеет высоту 3, но 4 узла.

J. Doe 03.04.2019 01:42

Но ранг равен трем, т.е. 3 имеет три фринда.

vijay 03.04.2019 01:45

Да, но мне не нужен ранг, мне нужно количество узлов в этом дереве. Вопрос касается самой большой группы друзей, а не того, у кого больше всего друзей.

J. Doe 03.04.2019 01:46

поэтому вам нужно добавить 1

vijay 03.04.2019 01:47

Но чем это отличается от простого поиска с использованием родительского массива?

J. Doe 03.04.2019 01:48

потому что parent[i] дает вам родителя человека i, а не количество его друзей

vijay 03.04.2019 01:50

Родительский массив хранит корневой узел во всех дочерних элементах дерева. Я использую гистограмму для подсчета, затем нахожу макс.

J. Doe 03.04.2019 01:51
Ответ принят как подходящий

Цикл for, который вы вставили union, портит производительность. Просто выньте это.

В цикле гистограммы вам нужно int root = find(j,parent);

Ваш код выдает исключение, когда numcitizens равно нулю.

Исправьте это, и ваш код, я думаю, будет работать.

Вот пара дополнительных советов:

  • Я всегда объединяю по размеру, а не по рангу. Он имеет ту же сложность, и размер часто бывает полезен. В этом случае вам не нужно было бы строить гистограмму, потому что у вас был бы размер каждого корня прямо здесь.

  • Я использую один массив int[] для структуры данных. Если значение в >=0, то это корневой набор с таким размером (0 означает, что по этому индексу нет набора или пустого набора). В противном случае ~v является ссылкой на родительский набор. Недавно я использовал эту структуру в этом ответе: Алгоритм: используйте union find для подсчета количества островов

Другие вопросы по теме