什么是并查集?
并查集(Disjoint-Set)是一种可以动态维护若干个不重叠的集合,并支持合并与查询的数据结构,它名字的含义为“合并”、“查找”、“集合”,包括两种基本操作:
1. 查找:查询一个元素属于哪个集合以及两个元素是否属于同一个集合;
2. 合并:将两个集合合并成一个大集合。
怎么实现并查集?
在这篇博客里,我将从并查集最朴素的实现方法开始展示,并进行逐步优化。
首先,为了具体实现并查集,我们需要定义集合的表示方法。在并查集中,我们采用代表元法,即为每个集合选择一个固定的元素,作为整个集合的“代表”。你可以认为这是给每个集合选出一位班长,用它来代表这个集合。
其次,我们需要定义归属关系的表示方法。
实现方法一:QuickFind
查找快,合并慢的一种方法。
第一种思路,是维护一个数组f,用f[x]保存元素x所在集合的“代表”,即朴素解法。
set[i] 1 2 1 4 2 6 1 6 2 2
i 1 2 3 4 5 6 7 8 9 10
在上面表格中,我们的实现方法如下:
1. 用set[i]来表示元素i所属的集合;
2.并用该集合中最小的元素作为代表来标记这个集合
你不难发现,上面的集合是{1, 3, 7},{4},{2, 5, 9, 10},{6, 8}。
并查集的基本操作:
初始化:
void init(int N){
for(int i = 1; i <= N; ++i){
fa[i] = i;
}
}
/*
我们需要让每个元素的父亲结点不存在或指向自己
所以father[i] = -1也可以
*/
查找:
int Find(int x){
return x == father[x] ? x : (father[x] = Find(father[x]));
}
//注意? :运算符优先级较高,要加上括号
合并:
void Merge(int a, int b){
int faA = Find(a); //查找a的根节点
int faB = Find(b); //查找b的根节点
if(faA != faB){ //如果不属于同一集合
fa[faA] = faB; //合并它们
}
}
题目链接:并查集
题解:就是并查集的基本操作,合并集合,查找;最后判断是不是一个集合即可;
AC代码:
#include <iostream>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <cstdio>
#include <stack>
#include <queue>
using namespace std;
using ll = long long;
#define up(h,n) for(int i=h;i<=n;i++)
#define down(h,n) for(int i=h;i>=n;i--)
#define wh(x) while(x--)
#define node struct node
#define ios ios::sync_with_stdio(false)
constexpr int N = 200005;
constexpr int mod = 1e9 + 7;
typedef int SElemType;
int n, m;
int a[N];
int find(int x) {
if (a[x] == x) return x;
return a[x] = find(a[x]); //寻找集合老大
}
int main() {
cin >> n >> m;
up(1, n) {
a[i] = i; //先让自己为集合老大
}
wh(m) {
int x, y, z;
cin >> x >> y >> z;
if (x == 1) {
a[find(y)] = find(z); // 合并集合
}
else if (find(y) == find(z)) {
cout << 'Y' << '\n';
}
else cout << 'N' << '\n';
}
return 0;
}
题目链接:亲戚
题解:这个题也一样就是并查集的一些基本操作废话不多说看代码;
AC代码:
#include <iostream>
#include <cstring>
#include <cmath>
#include <iomanip>
#include <algorithm>
#include <cstdio>
#include <stack>
#include <queue>
using namespace std;
using ll = long long;
#define up(h,n) for(int i=h;i<=n;i++)
#define down(h,n) for(int i=h;i>=n;i--)
#define wh(x) while(x--)
#define node struct node
#define ios ios::sync_with_stdio(false)
constexpr int N = 100005;
constexpr int mod = 1e9 + 7;
int n, m,p;
int a[N];
int find(int x) {
if (a[x] == x) return x;
return a[x] = find(a[x]); // 查找
}
void fun(int c, int b) {
a[find(c)] = find(b); //合并集合
}
int main() {
cin >> n >> m >> p ;
up(1, n) {
a[i] = i; // 初始化
}
wh(m)
{
int x, y;
cin >> x >> y;
fun(x, y);
}
up(1, p) {
int x, y;
cin >> x >> y;
if (find(x) == find(y)) {
cout << "Yes" << '\n';
}
else cout << "No" << '\n';
}
return 0;
}