并查集及优化(路径压缩+按秩合并)
并查集(Disjoint-Set)是一种可以动态维护若干个不重叠的集合,并支持合并与查询两种操作的一种数据结构。
优秀博客链接:并查集的两种优化(按秩合并,路径压缩)
并查集特性
- 并查集是一个森林,pre[]存放父结点
- Find()操作——可以查询任一结点的根结点并返回、判断两个节点是否属于同一个集合(是否属于同一个根节点下)
- Merge()操作——实现两个不同集合的合并
——————————————代码————————————————1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20int pre[100005]; //父亲
void Init(int m) //初始化,每个节点的根就是自身
{
for(int i = 1; i <= m; ++i)
{
pre[i] = i;
}
}
int Find(int x) //查询树根
{
while(pre[x]!=x)
{
x = pre[x];
}
return x;
}
void Merge(int x, int y) //合并x和y所属的集合
{
pre[Find(x)] = pre[Find(y)];
}
并查集优化
两种优化方式都是为了尽可能降低树的深度。
- 路径压缩
Find()查询树根中让路径中的每个节点直接指向根结点pre[x]=pre[pre[x]];
- 按秩合并
runk[]记录某节点的高度
Merge()合并时让高度小的树合并到高度大的树
——————————————代码————————————————1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30int pre[N]; //父亲
int runk[N]; //高度
int Find(int x) //查询树根
{
while(pre[x]!=x)
{
pre[x]=pre[pre[x]]; //路径压缩
x = pre[x];
}
return x;
}
void Merge(int x, int y) //合并x和y所属的集合
{
int xe = Find(x);
int ye = Find(y);
if(xe!=ye)
{
if(runk[xe]>=runk[ye])
{
pre[ye] = xe;
runk[xe] = max(runk[xe], runk[ye]+1);
}
else
{
pre[xe] = ye;
runk[ye] = max(runk[ye], runk[xe]+1);
}
}
}
例题·蓝桥
题目来源:合根植物
算法思想
直接返回不同的集合数
连根现象即通过Merge()令两个结点属于同一集合
于是初始化pre[i] = i
然后该合并的合并
最后通过Find(i)==i
来确定不同的集合数
——————————————完整代码————————————————
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!