合并
路径压缩
例题:L2-2 冰岛人 - 2019年团体程序设计天梯赛-总决赛 (pintia.cn)
实现代码:
import java.util.ArrayList;
import java.util.Scanner;
class Person {
String firstName;
String sex;
public Person(String firstName, String sex) {
super();
this.firstName = firstName;
this.sex = sex;
}
}
public class Main {
static int[] tree;
static ArrayList<Integer> family = new ArrayList<Integer>();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
ArrayList<String> allName = new ArrayList<String>();
Person[] per = new Person[N];
tree = new int[N]; //家庭树,建立并查集
sc.nextLine();
//构建家庭树
for(int i=0;i<N;i++) {
String Name = sc.nextLine();
String[] name = Name.split(" ");
//男后裔
if(name[1].indexOf("sson")!=-1) {
name[1] = name[1].replace("sson", "");
per[i] = new Person(name[0], "m");
}
//女后裔
else if(name[1].indexOf("sdottir")!=-1) {
name[1] = name[1].replace("sdottir", "");
per[i] = new Person(name[0], "f");
}
//男祖先
else if(name[1].charAt(name[1].length()-1)=='m') {
per[i] = new Person(name[0], "m");
}
//女祖先
else if(name[1].charAt(name[1].length()-1)=='f') {
per[i] = new Person(name[0], "f");
}
allName.add(name[0]); //存储名字
//根据其父亲是否存在建立并查集队列
int index = allName.indexOf(name[1]);
if(index == -1)
tree[i] = i;
else
tree[i] = index;
}
//查询
N = sc.nextInt();
sc.nextLine();
for(int i=0;i<N;i++) {
String Name = sc.nextLine();
String[] name = Name.split(" ");
int index1 = allName.indexOf(name[0]);
int index2 = allName.indexOf(name[2]);
if(index1!=-1 && index2!=-1) {
if(per[index1].sex.equals(per[index2].sex)) {
System.out.println("Whatever");
}
else {
if(find(index1)!=find(index2) || judge(index1, index2)) {
System.out.println("Yes");
}
else {
System.out.println("No");
}
}
}
else {
System.out.println("NA");
}
}
}
//并查集查找
public static int find(int i) {
if(tree[i]!=i) {
return find(tree[i]);
}
else
return i;
}
public static boolean judge(int index1, int index2) {
int ret = 1;
while (index1 != tree[index1] && index2 != tree[index2]) {
index1 = tree[index1];
index2 = tree[index2];
++ret;
if (ret == 5) return true; //不在五代以内
if (index1 == index2) return false; //五代以内存在共同祖先
}
return false;
}
}
ac代码:
import java.util.*;
public class Main {
static int N = 1010,T;
static int n,idx;
static long h,r;
static int[] p = new int[N];
static long[] x = new long[N];
static long[] y = new long[N];
static long[] z = new long[N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
T = sc.nextInt();
for (int i = 0;i < T;i++) {
n = sc.nextInt();
h = sc.nextLong();
r = sc.nextLong();
init(n); //初始化p数组,使所有点都指向自己
for (int j = 1;j <= n;j++) {
x[j] = sc.nextLong();
y[j] = sc.nextLong();
z[j] = sc.nextLong();
if (z[j] <= r) { //和下表面相切或相交的情况
p[find(j)] = find(1001);
}
if (z[j] >= h - r) { //和上表面相切或相交的情况
p[find(j)] = find(1002);
}
}
for (int j = 1;j <= n;j++) {
for (int k = j+1;k <= n;k++) {
if(next_to(x[j], y[j], z[j], x[k], y[k], z[k], r)){
p[find(j)] = find(k);
}
}
}
System.out.println(find(1001) == find(1002) ? "Yes" : "No"); // 判断上表面是否和下表面属于一个集合。
}
}
static void init(int n) {
for (int i = 1;i <= n;i++) {
p[i] = i;
}
p[1001] = 1001; //1001表示与下表面相切或相交
p[1002] = 1002; //1001表示与下表面相切或相交
}
static int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
static boolean next_to(long x1, long y1, long z1, long x2, long y2, long z2, long r){
return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2) <= 4 * r * r;
}
}