并查集的应用

球迷

★实验任务
在大学里,有 n 个学生,每个的学生都有自己喜爱的球星,已知有 m 对学生喜爱的球星相同,问你这 n 个学生喜爱的球星最多可以有多少个。

★数据输入
输入第一行为一个正整数 n,m。
接下来 m 行,每行输入 ai,bi,表示 ai 同学和 bi 同学喜爱的球星一样
80%的数据 1<=n,m<=1000. 100%的数据 1<=n,m<=100000.

★数据输出
输出一个正整数,表示答案。

输入示例 输出示例
10 9 1
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10

输入示例 输出示例
10 4 7
2 3
4 5
4 8
5 8

解题思路

一、采用并查集的数据结构。

二、初始时,将每一个学生都当作一个独立的树,当有学生喜欢的球星相同时,将两个树合并。

三、建立全局变量id[max],size[max],count。其中id[i]的值代表i的父亲,初始化id[i]=i,指向本身。 size[i]表示i所在的树的元素个数,初始化为1。count表示有几个集合。

四、自定义函数find,union。find(p)用于查找p的祖先。union用来合并两个树,总是将元素少的合并到元素多的那里,这样使树保持扁平状,有利于查找祖先。

#include <iostream>
#include <cstdio>
#define max 100001
int count; 
int id[max];
int size[max];

int find(int p)
{
	while(p!=id[p])
	{
		id[p]=id[id[p]];
		p=id[p];//取它的爷爷节点,更快找到它的祖先
	}
	return p;
}

void Union(int x,int y)
{
	int p=find(x);
	int q=find(y);
	if(p==q)//如果有相同的根,就跳出 
		return ;	
	else if(size[p]>size[q])
	{
		id[q]=p;
		size[p]+=size[q];
	}
	else
	{
		id[p]=q;
		size[q]+=size[p];
	}
	count--;
}

using namespace std; 
int main()
{
	int n,m,i,j,a,b;
	scanf("%d %d",&n,&m);
	//cin >> n >> m ;
	count = n;
	for(i=0;i<n;i++)
		id[i]=i;//id 的值代表i的父亲节点 
	for(i=0;i<m;i++)
		size[i]=1;	//代表和i在相同的组的元素个数 
	for(i=0;i<m;i++)
	{
		scanf("%d %d",&a,&b);
		//cin >> a >> b;//输入一对喜欢相同明星的同学 
		int p=a-1;
		int q=b-1; 
		Union(p,q);
	}
	printf("%d",count);
	//cout << count;
	return 0;
 } 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值