定义
并查集是一种树形数据结构,实际使用数组进行存储,用于处理一些不相交集合的合并及查询问题。
主要由find和join函数组成。
find函数,查找结点的根结点
public static int find(int k) {
if (pre[k]==k)return k;//根节点返回
else return pre[k]=find(pre[k]);//为此树下的所有结点的父节点都设置成根节点,降低时间复杂度
}
join函数,将两个不相交的树合并
public static void join(int a,int b) {
int fa=find(a),fb=find(b);
if (fa!=fb)pre[fa]=fb;
}
并查集在经历过几轮查找和合并操作后时间复杂度会降到o(1)级别。
P8654 [蓝桥杯 2017 国 C] 合根植物
算是个模板题了
package 并查集;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class P8654合根植物 {
static int[] pre=new int[1000005];
public static void init(int n,int m) {
for(int i=1; i<=n*m; i++)
pre[i]=i;
}
public static int find(int x) {
if (pre[x]==x)return x;
else return pre[x]=find(pre[x]);
}
public static void join(int a,int b) {
int fa=find(a),fb=find(b);
if (fa!=fb)pre[fa]=fb;
}
public static void main(String[] args) {
int m,n,k,a,b,ans=0;
Scanner in=new Scanner(System.in);
m=in.nextInt();n=in.nextInt();k=in.nextInt();
init(m,n);
while(k--!=0){
a=in.nextInt();b=in.nextInt();
join(a,b);
}
for (int i = 1; i <= n*m; i++) {
if (i==pre[i])ans++;
}
System.out.println(ans);
}
}
P8686 [蓝桥杯 2019 省 A] 修改数组
主要运用了路径压缩来降低时间复杂度
package 并查集;
import java.io.*;
public class P8686修改数组 {
static int[] pre = new int[2000005],vis=new int[2000005];
public static void init(int n) {
for (int i = 1; i <= 2000004; i++) {
pre[i]=i;
}
}
public static int find(int x) {
if (pre[x] == x) return x;
else return pre[x] = find(pre[x]);
}
public static void main(String[] args) throws IOException {
int n;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
n=Integer.parseInt(in.readLine());
init(n);
String[] a=in.readLine().split(" ");
for (int i = 1; i <= n; i++) {
//未访问过
if (vis[Integer.parseInt(a[i-1])]==0){
out.print(a[i-1]+" ");
vis[Integer.parseInt(a[i-1])]=1;pre[Integer.parseInt(a[i-1])]=Integer.parseInt(a[i-1])+1;
}else {
//访问过
int fa = find(Integer.parseInt(a[i-1]));
vis[fa]=1;pre[fa]=fa+1;//设置父节点为fa+1,在下次查找时,自动找到下一个能用的结点,并将所有与之相关的结点修改
out.print(fa+" ");
}
}
out.flush();
}
}
P2949 [USACO09OPEN]Work Scheduling G
贪心+并查集
package 贪心;
import java.util.*;
public class P2949_Work_Scheduling_G {
//并查集在运行一段时间后可以将一段数据都连起来
static class task{
int d,p;
}
static Map<Integer,Integer> m=new HashMap<>();
static int n;
public static int find(int x) {
if (!m.containsKey(x)){
m.put(x,x);
}
if (m.get(x)==x)return x;
else {
//要注意put函数返回的值是键值之前对应的值,所以不能写成注释的形式
int t=find(m.get(x));
m.put(x,t);
return t;
}
//return m.get(x)==x?x:m.put(x,find(m.get(x)));
}
public static void join(int a,int b) {
int fa=find(a),fb=find(b);
if (fa!=fb)m.put(fa,fb);
}
public static void main(String[] args) {
long ans=0;
task t[]=new task[100005];
Scanner in=new Scanner(System.in);
n=in.nextInt();
for (int i = 1; i <= n; i++) {
t[i]=new task();
t[i].d=in.nextInt();
t[i].p=in.nextInt();
}
Arrays.sort(t, 1, 1 + n, new Comparator<task>() {
@Override
public int compare(task o1, task o2) {
return o2.p-o1.p;
}
});
int tt;
for (int i = 1; i <= n; i++) {
tt=find(t[i].d);
//以0为结束点,当tt为0时代表当前工作无天数安排
if (tt>=1) {
ans += t[i].p;
//m.put(tt, tt-1);
join(tt,tt-1);//当前工作日以被占,指向下一个可能可用工作日,如果可用下个工作直接占领,如果不可用,则该工作日又指向下一个可能可用工作日
}
}
System.out.println(ans);
}
}