基本介绍
并查集主要实现两个操作:
- 合并两个集合
- 查询某个元素的祖宗节点
并查集的两个优化:
- 路径压缩: O ( l o g n ) O(logn) O(logn)
- 按秩合并: O ( l o g n ) O(logn) O(logn),代码比较复杂,一般不单独用
两种优化结合起来用,时间复杂度可以压缩到 O ( α ( n ) ) O(\alpha(n)) O(α(n))
并查集的扩展
并查集在维护两个操作的同时,还可以进行以下扩展:
- 记录每个集合大小:绑定到根节点上
- 每个点到根节点的距离:绑定到每个元素上
格子游戏
题目描述
问题分析
形成环等价于两个点在连边之前,已经在一个集合里
程序代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 40010;
int n, m;
int p[N];
// 将二维坐标转换为一维上的点
int get(int x, int y)
{
return x * n + y;
}
int find(int x)
{
// 只有祖先节点的p[x]等于自身
if( p[x] != x ) p[x] = find(p[x]);
return p[x];
}
int main()
{
cin >> n >> m;
// 并查集初始化
for(int i = 0; i < n * n; i++) p[i] = i;
int res = 0;
for(int i = 1; i <= m; i++) {
int x, y;
char c;
cin >> x >> y >> c;
x--, y--;
int a = get(x, y);
int b;
// 向下连一条边
if(c == 'D') b = get(x + 1, y);
// 向右连一条边
else b = get(x, y + 1);
// 找到所属集合的祖先节点
int pa = find(a), pb = find(b);
// 形成环路,游戏结束
if(pa == pb) {
res = i;
break;
}
// 集合合并
p[pa] = pb;
}
if( res ) cout << res << endl;
else cout << "draw" << endl;
return 0;
}