Пример ввода:
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.
@Andreas Андреас, я обновил код самой последней функции else, чтобы исправить это; все еще говорит мне неправильный ответ
Количество друзей у каждого человека не равно 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);
Ранг - это высота. Я не пытаюсь получить наибольшую глубину, я пытаюсь получить наибольшее количество узлов
В этом случае высота также является количеством узлов
Как? Дерево типа 3-4-1-2 без сжатия пути имеет высоту 3, но 4 узла.
Но ранг равен трем, т.е. 3 имеет три фринда.
Да, но мне не нужен ранг, мне нужно количество узлов в этом дереве. Вопрос касается самой большой группы друзей, а не того, у кого больше всего друзей.
поэтому вам нужно добавить 1
Но чем это отличается от простого поиска с использованием родительского массива?
потому что parent[i] дает вам родителя человека i, а не количество его друзей
Родительский массив хранит корневой узел во всех дочерних элементах дерева. Я использую гистограмму для подсчета, затем нахожу макс.
Цикл for, который вы вставили union
, портит производительность. Просто выньте это.
В цикле гистограммы вам нужно int root = find(j,parent);
Ваш код выдает исключение, когда numcitizens
равно нулю.
Исправьте это, и ваш код, я думаю, будет работать.
Вот пара дополнительных советов:
Я всегда объединяю по размеру, а не по рангу. Он имеет ту же сложность, и размер часто бывает полезен. В этом случае вам не нужно было бы строить гистограмму, потому что у вас был бы размер каждого корня прямо здесь.
Я использую один массив int[]
для структуры данных. Если значение в >=0, то это корневой набор с таким размером (0 означает, что по этому индексу нет набора или пустого набора). В противном случае ~v является ссылкой на родительский набор. Недавно я использовал эту структуру в этом ответе: Алгоритм: используйте union find для подсчета количества островов
Попробуйте ввести
1
,4 3
,1 2
,3 4
,4 1
. Результатом должно быть то, что цепочка друзей3-4-1-2
имеет размер 4, но ваш код печатает 3.