文章目录
- 并查集
- 并查集引入
- 1.初始化
- 2.查询
- 3.合并
- 路径压缩
- 代码模板
- (1)朴素并查集:
- (2)维护size的并查集:
- (3)维护到祖宗节点距离的并查集:
并查集
并查集引入
并查集(Union-find Sets)是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题。一些常见的用途有求联通子集、求最小生成树的Kruskal算法和求最近公共祖先(LCA)等。
并查集的基本操作主要有:
- 初始化init
- 查询find
- 合并unionn
1.初始化
int fa[MAXN];
void init(int n)
{for(int i=1;i<=n;i++)fa[i]=i;
}
假设有编号为1,2,3……,n的n个元素,我们用一个数组fa[]来存储每个元素的父节点。一开始,我们先将它们的父节点设为自己。
2.查询
找到i的祖先直接返回,未进行路径压缩
int find(int i)
{if(fa[i]==i)//递归出口,当到达了祖先位置,就返回祖先return i;elsereturn find(fa[i]);//不断往上查找祖先
}
3.合并
void unionn(int i,int j)
{int i_fa=find(i);//找到i的祖先int j_fa=find(j);//找到j的祖先fa[i_fa]=j_fa;//i的祖先指向j的祖先。
}
路径压缩
int find(int i)
{if(i==fa[i])return i;else {fa[i]==find(fa[i]);//该步进行了路劲压缩return fa[i];//返回父节点}
}
代码模板
(1)朴素并查集:
int p[N]; //存储每个点的祖宗节点// 返回x的祖宗节点int find(int x){if (p[x] != x) p[x] = find(p[x]);return p[x];}// 初始化,假定节点编号是1~nfor (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~nfor (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)维护到祖宗节点距离的并查集:
int p[N], d[N];//p[]存储每个点的祖宗节点, d[x]存储x到p[x]的距离// 返回x的祖宗节点int find(int x){if (p[x] != x){int u = find(p[x]);d[x] += d[p[x]];p[x] = u;}return p[x];}// 初始化,假定节点编号是1~nfor (int i = 1; i <= n; i ++ ){p[i] = i;d[i] = 0;}// 合并a和b所在的两个集合:p[find(a)] = find(b);d[find(a)] = distance; // 根据具体问题,初始化find(a)的偏移量