1.并查集简介
并查集被很多OIer认为是最简洁而优雅的数据结构之一,主要用于解决一些元素分组的问题。它管理一系列不相交的集合,并支持两种操作:
- 合并(Union):把两个不相交的集合合并为一个集合。
- 查询(Find):查询两个元素是否在同一个集合中。
它可以解决很多连通性的问题!!!
2.并查集模版
(1)朴素并查集:
int p[N]; //存储每个点的祖宗节点
// 返回x的祖宗节点
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
// 初始化,假定节点编号是1~n
for (int i = 1; i <= n; i ++ ) p[i] = i;
// 合并a和b所在的两个集合:
p[find(a)] = find(b);
(2)维护size的并查集:
int p[N], size[N];
//p[]存储每个点的祖宗节点, size[]只有祖宗节点的有意义,表示祖宗节点所在集合中的点的数量
// 返回x的祖宗节点
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
// 初始化,假定节点编号是1~n
for (int i = 1; i <= n; i ++ )
{
p[i] = i;
size[i] = 1;
}
// 合并a和b所在的两个集合:
size[find(b)] += size[find(a)];
p[find(a)] = find(b);
3.七段码
每一个字符有发光和不发光两种状态,我们可以轻易地想到用DFS来枚举每个字符的每种状态,如果该字符i和字符j存在边且同时量,就可以合并。
如果最后只有一个连通分量,则ans++;
//省赛真题,七段码;
public class Test01 {
static int ans=0;
static int[]p=new int[8];
static boolean[][]e=new boolean[8][8];
static boolean[]st=new boolean[8];
public static void main(String[] args) {
e[1][2] = e[1][6] = true;
e[2][1] = e[2][7] = e[2][3] = true;
e[3][2] = e[3][7] = e[3][4] = true;
e[4][3] = e[4][5] = true;
e[5][4] = e[5][7] = e[5][6] = true;
e[6][1] = e[6][7] = e[6][5] = true;
e[7][2] = e[7][3] = e[7][5] = e[7][6] = true;
dfs(1);
System.out.println(ans);
}
public static void dfs(int u){
if(u>7){
//初始化并查集;
for (int i = 1; i <=7 ; i++) {
p[i]=i;
}
for (int i = 1; i <=7 ; i++) {
for (int j = 1; j <=7 ; j++) {
if(e[i][j]&&st[i]&&st[j]){
p[find(i)]=find(j);
}
}
}
int cnt=0;
for (int i = 1; i <=7; i++) {
if(st[i]&&p[i]==i){
cnt++;
}
}
if(cnt==1){
ans++;
}
return;
}
st[u]=true;
dfs(u+1);
st[u]=false;
dfs(u+1);
}
public static int find(int x){
if(p[x]!=x){
p[x]=find(p[x]);
}
return p[x];
}
}
4.合根植物
并查集可以维护连通性,一看这个图就能用并查集来做!!!
每次输入两个值,如果它们不连通,就合并它们,接着检查有几个连通分量!!!
import java.util.Scanner; public class Main { static int N=1000010; static int[]p=new int[N]; static int res=0; public static void main(String[] args) { Scanner sc=new Scanner(System.in); int m=sc.nextInt(); int n=sc.nextInt(); int k=sc.nextInt(); for (int i = 1; i <=n*m ; i++) { p[i]=i; } while(k--!=0){ int a=sc.nextInt(); int b=sc.nextInt(); if(p[a]!=p[b]) p[find(a)]=find(b); } for (int i = 1; i <=n*m ; i++) { if(p[i]==i){ res++; } } System.out.println(res); } public static int find(int x){ if(p[x]!=x){ p[x]=find(p[x]); } return p[x]; } }