并查集-1

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

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

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

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


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

题目描述:
世界上有许多不同的宗教,现在有一个你感兴趣的问题:找出不同的宗教种数,在你的大学中的大学生信仰了多少种不同的宗教。在你的大学有n个学生(0<n<=50 000)。若直接问一个每一个学生的宗教信仰不太适合。此外,许多学生不太愿意说出自己的信仰。有一种方法来避免这个问题,询问m(0=<m<=n(n-1)/2)对学生,询问他们是否信仰同一个宗教(可以询问他们是否都参加同一教堂)。从这个数据,你可能不知道每个人的宗教信仰,但是你可以知道有多少种不同宗教信仰。可以假设,每名学生最多信仰一个宗教。
输入:
输入包含多组测试数据。每组测试数据的开头包含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<stdio.h> 
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数组下标所对应数组中的值

12345678910
12345678910

sum=10

make(1,2)

12345678910
11345678910
sum = 9
make(1,3)

12345678910
11145678910

sum=8

...

make(1,10)

12345678910
1111111111
sum = 1


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值