目录

蓝桥杯备考并查集

目录

蓝桥杯备考:并查集

要学并查集,首先我们得知道什么是双亲表示法,我们之前学树的时候,是用的孩子表示法,双亲表示法又是什么呢?首先,我们的并查集实际上就是一个森林

https://i-blog.csdnimg.cn/direct/dcd5468682cf44dfa8216b332b9f5896.png

双亲表示法就是把每个结点的双亲存下来,比如2结点的双亲是1,下标为2就放的是1

当我们把每个结点的父亲都存下来,就完成了

不过,在实现并查集的时候,我们一般都把根节点的双亲标志为它自己

https://i-blog.csdnimg.cn/direct/ccf5c4fe41254c4c920fe4d7ed3cc90c.png

并查集的概念:

并查集,就是合并集合,查询集合元素的一个数据结构

比如我们有三个集合 https://i-blog.csdnimg.cn/direct/73398ded9bb845ca86956fcb37299d39.png

我们需要频繁进行三个操作①查询操作,我们每个集合都有一个代表元素,比如第一个集合代表元素就是1,第二个集合代表元素就是6,第三个集合代表元素就是8,我们要查询某个元素是位于哪个集合里

②合并操作,我们要合并某两个集合,参数就是两个代表元素

③判断操作,判断两个元素是不是在一个集合里,我们只要看两个元素的集合的代表元素是不是同一个就行了

比如find(11)就是8,find(9)也是8  find(3)是1,find(6)是7

thesame(10,11)是对的

union(7,2)就是合并6和1代表的俩集合

这就差不多是并查集要实现的功能

不过我们要真正实现并查集,必须要用到树,用到森林

我们需要把这些集合分别弄成每棵树,用双亲表示法表示,代表元素就是根节点

https://i-blog.csdnimg.cn/direct/1b560915695f4f16896336114a85b8bf.png

三大操作 一/find 我们只需要根据find的值不断向上找根节点就可

https://i-blog.csdnimg.cn/direct/39ac392734e44cb5a075a33875651d4d.png

如图这就是我们find的函数,就是不断的向上找根节点不断的向上找根节点,当找到根节点的时候返回

二/union 我们只需要找到根节点,然后把一方的根节点挂在另一方即可

https://i-blog.csdnimg.cn/direct/f63603f95c1345a8ac2aeb1c65267e1b.png

三/thesame 我们只要用两个find 比较根节点是不是一样的就行

https://i-blog.csdnimg.cn/direct/cd26f0bf4cd7458fbac593524a44a62c.png

但是仅仅这样还是不够的,我们想象出一个极端的例子 https://i-blog.csdnimg.cn/direct/fc111741a4fe46d393e522c11d916c1e.png

我们合并的时候,如果一直让长的挂在短的后面,就会形成一个类似链表的东西,这时候我们再进行查询就是O(N)级别的了

我们怎么优化?

我们可以让每次find的时候,在回溯的过程中,让遍历到的每个结点都变成这个根节点的孩子

https://i-blog.csdnimg.cn/direct/7117692b23cd404cb8a350e99fda4800.png

https://i-blog.csdnimg.cn/direct/04504b5e1a5642adb95b79ab396a02a8.png

差点忘记说了,我们的并查集是需要初始化的

https://i-blog.csdnimg.cn/direct/9c10abb0f63c4d67a284ff3d6f635b55.png

完整代码

#include <iostream>
using namespace std;

void init()
{
	for(int i = 1;i<=n;i++)
	{
		fa[i] = i;
	}
}
int find(int x)
{
	if(fa[x] == x) return x;
    return fa[x] = find(fa[x]);
	//return fa[x] == x ? x  : find(fa[x]);
} 

void un(int x,int y)
{
	int px = find(x);
	int py = find(y);
	fa[px] = py;
}

bool thesame(int x,int y)
{
	return find(x) == find(y);
}

好,接下来我们来做一道模板题

https://i-blog.csdnimg.cn/direct/4f083c9712014ca596570f172c01a16a.png

#include <iostream>
using namespace std;
const int N  = 2e5+10;
int fa[N];
int n,m;
int find(int x)
{
	if(fa[x] == x) return x;
	return fa[x] = find(fa[x]);
	
}
void un(int x,int y)
{
	int dx = find(x);int dy = find(y);
	fa[dx] = dy;
}
bool isthesame(int x,int y)
{
	return find(x) == find(y);
}
int main()
{
	cin >> n >> m;
	for(int i = 1;i<=n;i++)
	{
		fa[i] = i;
	}
	while(m--)
	{
		int op,x,y;cin >> op >> x >> y;
		if(op == 1) un(x,y);
		else if(op == 2)
		{
			if(isthesame(x,y)) cout << "Y" << endl;
			else cout << "N" << endl;
		}
		
	}
	
	
	
	
	
	return 0;
}