点击查看代码
#include<cstdio>
#pragma warning(disable:4996)
//并查集的基本操作
const int maxn = 1001; //最多1000个元素
int n; //并查集元素个数
int father[maxn]; //存储并查集元素
//查找元素x所在集合的根结点
int findFather(int x) {
while (x != father[x]) { //如果x不是根结点,则继续向根结点方向查找
x = father[x]; //将x的父结点作为下一轮的查找结点
}
}
/*优化后的查找函数(非递归版本)
(1)按照优化前的查找函数方法,获得元素x的根结点r
(2)从元素x出发,重新走一遍查找根结点的路径,将路径上经过的所有结点的父结点都改为根结点r */
int findFatherOptimize(int x) {
int temp = x; //先存储x的副本,在下面的while中会修改x
//步骤1,查找元素x的根结点,while循环结束后,x存储的是根结点
while (x != father[x]) { //只要x不是根结点,就继续回溯父结点
x = father[x];
}
//步骤2,重走一次元素x(即temp)查找根结点的路径,将路径上所有结点的父结点都设为根结点
while (temp != father[temp]) { //只要temp不是根结点,就继续回溯父结点
int z = temp; //先存储temp的副本,因为temp在下面会被修改
temp = father[temp]; //将temp的父结点赋给temp,准备下一轮查找
father[z] = x; //将temp的父结点改为根结点x
}
return x; //返回根结点
}
//优化后的查找函数(递归版本)
int findFatherRecursion(int x) {
if (x == father[x]) return x; //返回根结点x
else {
int root = findFatherRecursion(father[x]); //递归查找根结点root
father[x] = root; //将查找路径上的所有结点的父结点都设为根结点
return root; //返回根结点
}
}
//合并元素a和元素b的两个集合
void Union(int a, int b) {
int faA = findFather(a); //查找a所在集合的根结点,存入faA中
int faB = findFather(b); //查找b所在集合的根结点,存入faB中
//两个元素不在同一个集合时才进行合并,因此并查集产生的每一个集合都是一棵树,不会出现环
if (faA != faB) {
father[faA] = faB; //将faA的父结点设置为faB,合并两个集合
}
}
int main() {
//并查集初始化
for (int i = 1; i <= n; i++) {
father[i] = i; //每个元素的父结点为自己,每个元素都是根结点
}
return 0;
}