球迷
★实验任务
在大学里,有 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;
}