并查集
一、并查集的相关操作
-
并查集是一种树形数据结构,它的两种主要操作是:查找、合并。
-
查找(find):确定某个元素处于哪个子集。
-
合并(union):将两个子集合并成一个集合。
-
代码实现
-
初始化initial
void init(int n){ for(int i=1;i<=n;i++){ fx[i]=i;//每个i都属于一个集合 } }
-
查找(find)
int find(int x){ if(fx[x]==x){ return x; }else{ return find(fx[x]); } }
-
合并(union)
void union(int a,int b){ fx[find(a)]=find(b); }
-
二、并查集的相关题目
-
宗教信仰问题
【问题描述】
世界上有许多宗教,你感兴趣的是你学校里的同学信仰多少种宗教。
你的学校有n名学生(0 < n <= 50000),你不太可能询问每个人的宗教信仰,因为他们不太愿意透露。但是当你同时找到2名学生,他们却愿意告诉你他们是否信仰同一宗教,你可以通过很多这样的询问估算学校里的宗教数目的上限。你可以认为每名学生只会信仰最多一种宗教。
【输入形式】
输入包括多组数据。
每组数据的第一行包括n和m,0 <= m <= n(n-1)/2,其后m行每行包括两个数字i和j,表示学生i和学生j信仰同一宗教,学生被标号为1至n。输入以一行 n = m = 0 作为结束。
【输出形式】
对于每组数据,先输出它的编号(从1开始),接着输出学生信仰的不同宗教的数目上限。
【样例输入】
10 9
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
10 4
2 3
4 5
4 8
5 8
0 0
【样例输出】
Case 1: 1
Case 2: 7
-
代码实现
#include<iostream> using namespace std; int fx[50001]; void init(int n){ for(int i=1;i<=n;i++){ fx[i]=i; } } int find(int x){ if(fx[x]==x){ return x; }else{ return find(fx[x]); } } void join(int a,int b){//union是c++中的关键字,可能无法通过编译,换个名字。 fx[find(a)]=find(b); } int main(){ int n,m; int tmp=0; while((scanf("%d %d",&n,&m))&&n!=0&&m!=0){ int count=n; tmp++; init(n); while(m--){ int a,b; cin>>a>>b; if(find(a)!=find(b)){ join(a,b); count--; } } cout<<"Case "<<tmp<<": "<<count<<endl; } return 0; }