并查集-1

并查集是一种树型的数据结构,用于处理一些不相交集合(disjoint sets)的合并及查询问题。经常采用树林来表示:

1. 查找。查找元素所在的集合即查找根节点。

2. 合并。将两个元素所在的集合合并为一个集合。

3. 合并两个不相交的集合判断两个元素是否属于同一个集合。


我们结合相应的题目来说:

题目描述:
世界上有许多不同的宗教,现在有一个你感兴趣的问题:找出不同的宗教种数,在你的大学中的大学生信仰了多少种不同的宗教。在你的大学有n个学生(0 输入:
输入包含多组测试数据。每组测试数据的开头包含2个整数n和m。接下来m行,每行有两个整数i和j,编号i和j的同学信仰同一宗教。学生的编号从1开始到n。当输入n=0,m=0时,则输入结束。
输出:
每组测试数据的输出只有一行,包含数据的组别(从1开始)和学生最多信仰的宗教数。
样例输入:
10 9
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10
2 3
4 5
4 8
5 8
0 0
样例输出:
Case 1: 1
Case 2: 7


分析:

1. 首先我们将每个人的都作为一个节点,初始化时每个节点的父亲节点都是节点本身。

2. 如果要让使不同的宗教信仰是最多的,就假设初始时每个人的宗教信仰不同,那么最大宗教信仰数目sum就是对应的人数,即sum = n

3. 每输入一对宗教信仰相同的人,并且这对人如果当前还属于不同的集合的话,则宗教信仰数-1,即sum--

4. 所有的输入都结束的时候,sum就是所求的结果。

#include 
int f[50010], sum;

int find(int x)
{
	if(f[x] != x)
		f[x] = find(f[x]);
	return f[x];
}

void make(int a, int b)
{
	int f1 = find(a);
	int f2 = find(b);
	if(f1 != f2)
	{
		f[f2] = f1;
		sum --;
	}
}

int main()
{
	int n, m ,p = 1, i;
	while(scanf("%d %d", &n, &m) != EOF)
	{
		if(n == 0 && m == 0)
			break;
		
		for(i = 1; i <= n; i ++)
			f[i] = i;
		
		sum = n;
		
		for(i = 1; i <= m; i ++)
		{
			int a, b;
			scanf("%d %d", &a, &b);
			make(a, b);
		}
		
		printf("Case %d: %d\n", p++, sum);
	}
	return 0;
}


第一组测试样例:第一行代表f数组的下标,第二行代表f数组下标所对应数组中的值

1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10

sum=10

make(1,2)

1 2 3 4 5 6 7 8 9 10
1 1 3 4 5 6 7 8 9 10
sum = 9
make(1,3)

1 2 3 4 5 6 7 8 9 10
1 1 1 4 5 6 7 8 9 10

sum=8

...

make(1,10)

1 2 3 4 5 6 7 8 9 10
1 1 1 1 1 1 1 1 1 1
sum = 1


你可能感兴趣的:(ACM)