C++并查集详解

并查集(Union Find)是一种用于处理不相交集合的数据结构。它支持两个主要操作:合并(Union)和查找(Find)。

在并查集中,每个元素都有一个父节点指向它所属的集合的根节点。如果某个元素的父节点指向自身,则表示该元素为集合的根节点。

合并操作将两个集合合并为一个集合,即将一个集合的根节点的父节点指向另一个集合的根节点。这可以通过查找两个元素所属集合的根节点,并将其中一个的根节点的父节点指向另一个根节点来实现。

查找操作用于确定某个元素所属的集合。它通过递归地查找元素的父节点,直到找到根节点为止。根节点即为集合的代表元素。

并查集常用于解决一些集合类问题,比如判断两个元素是否属于同一个集合、求解连通分量等。它的时间复杂度取决于树的高度,在最坏情况下可能达到O(n)。

C++中可以使用数组来实现并查集。假设有n个元素,可以使用一个大小为n的数组parent来保存每个元素的父节点。初始时,每个元素的父节点都指向自身。

可以把这个过程想象成帮派火并,两个帮派合并的时候就让一帮人的上司变成另一帮人的上司,然后就变成了一群人。查找两个人是不是同一个帮派的时候只需要看两个人的上司是不是同一个就可以了。

以下是一个基本的C++实现:

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
int n,m,f[1000001],a,b;
char temp;
int find(int a){
	while(f[a]!=a) a=f[a];
	return f[a];
}
int main(){
	scanf("%d%d",&n,&m);
	rep(i,1,n) f[i]=i;
	while(m--){
		cin>>temp>>a>>b;
		int aa=find(a),bb=find(b);
		if(temp=='M') f[aa]=bb;//合并 
		else{//查找 
			if(aa==bb) printf("YES\n");
			else printf("NO\n");
		}
	}
}

在上面的代码中,find函数使用路径压缩优化来减小树的高度。f数组来表示合并时哪个集合作为父节点。

这只是一个简单的并查集实现,还可以根据具体需求进行改进和扩展。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是C++实现并查集解决格子游戏的代码和解释: ```cpp #include <iostream> #include <vector> using namespace std; const int MAXN = 1005; int f[MAXN * MAXN], rank[MAXN * MAXN]; int n, m; // 初始化并查集 void init() { for (int i = 1; i <= n * m; i++) { f[i] i; rank[i] = 1; } } // 查找根节点 int find(int x) { if (x != f[x]) { f[x] = find(f[x]); } return f[x]; } // 合并两个集合 void merge(int x, int y) { int fx = find(x); int fy = find(y); if (fx != fy) { if (rank[fx] < rank[fy]) { swap(fx, fy); } f[fy] = fx; rank[fx] += rank[fy]; } } int main() { cin >> n >> m; init(); vector<vector<int>> grid(n, vector<int>(m)); // 输入格子游戏的矩阵 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> grid[i][j]; } } // 遍历矩阵,合并相邻的格子 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (i > 0 && grid[i][j] == grid[i - 1][j]) { merge((i - 1) * m + j + 1, i * m + j + 1); } if (j > 0 && grid[i][j] == grid[i][j - 1]) { merge(i * m + j, i * m + j + 1); } } } // 统计不同集合的个数 int cnt = 0; for (int i = 1; i <= n * m; i++) { if (f[i] == i) { cnt++; } } cout << cnt << endl; return 0; } ``` 解释: 首先,我们需要定义一个并查集,用于维护格子之间的连通性。在这个并查集中,每个格子都是一个节点,如果两个格子相邻且颜色相同,则它们属于同一个集合。我们可以使用一个二维数组来表示格子游戏的矩阵,其中每个元素表示该位置的格子颜色。 接下来,我们需要遍历整个矩阵,对于每个格子,如果它和它上面或左边的格子颜色相同,则将它们合并到同一个集合中。这里我们使用路径压缩和按秩合并两种优化方式,可以提高查询效率。 最后,我们统计不同集合的个数,即为最终答案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值