为什么我针对这个问题的 Union Find Disjoint Sets 算法没有通过所有测试用例?
Why is my Union Find Disjoint Sets algo for this problem not passing all test cases?
示例输入:
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 问题。
每个人的好友数不是每个人的parent
array.Rank
是由集合表示的树的高度,即这个人拥有的朋友的数量。
所以在 for 循环中使用 root=rank[j]+1
来计算最大朋友数。
int max=Integer.MAX_VALUE;
for(int r:rank){
max=Math.max(max,r+1);
}
System.out.println(max);
您在 union
中放入的 for 循环破坏了性能。拿出来就好了
在直方图循环中,需要int root = find(j,parent);
当 numcitizens
为零时,您的代码抛出异常。
我认为,修复这些问题,您的代码就会正常工作。
这里有一些额外的提示:
我总是按大小联合而不是按等级联合。它具有相同的复杂性,并且大小通常很有用。在这种情况下,您不需要构建直方图,因为您已经掌握了每个根的大小。
我使用单个 int[]
数组作为数据结构。如果值 v >=0,则它是具有该大小的根集(0 表示该索引处没有集或空集)。否则 ~v 是父集的 link。我最近在这个答案中使用了该结构:
示例输入:
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 问题。
每个人的好友数不是每个人的parent
array.Rank
是由集合表示的树的高度,即这个人拥有的朋友的数量。
所以在 for 循环中使用 root=rank[j]+1
来计算最大朋友数。
int max=Integer.MAX_VALUE;
for(int r:rank){
max=Math.max(max,r+1);
}
System.out.println(max);
您在 union
中放入的 for 循环破坏了性能。拿出来就好了
在直方图循环中,需要int root = find(j,parent);
当 numcitizens
为零时,您的代码抛出异常。
我认为,修复这些问题,您的代码就会正常工作。
这里有一些额外的提示:
我总是按大小联合而不是按等级联合。它具有相同的复杂性,并且大小通常很有用。在这种情况下,您不需要构建直方图,因为您已经掌握了每个根的大小。
我使用单个
int[]
数组作为数据结构。如果值 v >=0,则它是具有该大小的根集(0 表示该索引处没有集或空集)。否则 ~v 是父集的 link。我最近在这个答案中使用了该结构: