2-1 每日总结

本文详细讲解了并查集,包括其定义、代表元素的选择和基本操作(查找和合并),并提供了两种实现方法及其优化。
摘要由CSDN通过智能技术生成

什么是并查集?


并查集(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;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值