并查集以及经典例题解析

版权声明:大佬们转载时别忘了我哦!!! https://blog.csdn.net/sun9979/article/details/87561783

并查集:union(合并),find(查找),set(集合)。
1)合并:合并两个集合。
2)查找:判断两个元素是否在一个集合。

1、首先得有一个father数组,其中father[i]=i,的意思就时father[i]表示元素i的父亲。

2、初始化!让他们都属于不同的集合,他们的父节点都是自己

for(int i = 1; i <= n; i++)
  	father[i] = i;				//也可以是-1

3、查找!可以用递推或者递归

int findFather(int x) 
{
  while(x != father[x])
    x = father[x];
  return x;
}

//或者递归
int findFather(int x)
 {
  if(x == father[x]) return x;
  else return findFather(father[x]);
}

4、合并!把两个集合合并为一个集合

void Union(int a, int b)				//应该写大写U,小写u好像会冲突
 {
  int faA = findFather(a);
  int faB = findFather(b);
  if(faA != faB)			
    father[faA] = faB;			//谁是谁父节点都无所谓,看想要谁,就让谁是谁的父节点
}

5、路径压缩!
以上的查找函数是没有经过优化的,在极端情况下效率极低,元素数量很多并形成一条链的时候,查找函数的效率贼低。
在这里插入图片描述

int findFather(int x)
{ 
	int a = x; 
	while(x != father[x]) 
		x = father[x]; 
	while(a != fahter[a]) { 			//路径压缩代码,可以省略 
		int z = a; 
		a = father[a]; 
		father[z] = x; 
	} 
	return x; 
}

经典例题:
PAT–L2-007家庭房产------并查集
PAT–L2-010排座位------并查集
PAT–L2-024部落------并查集(Union函数问题)
PAT–L3-003社交集群------并查集

大致总结一下一些所求的点:
1)当时对于什么共同的兴趣或者课程的时候,应为没有直接输入id,所以应该另外设置一个数组a,首先给每一个兴趣或者课程一个father,当a[b]==0时令a[b]=i。
2)怎么求集合的总个数?
怎么求每个集合的个数

int isRoot[10000]={0};
for(int i=1;i<=n;i++){
        if(isRoot[find(i)]==0) flag++;
        isRoot[find(i)]++;
    }

猜你喜欢

转载自blog.csdn.net/sun9979/article/details/87561783