(模板)并查集
题目描述:
体育课上,体育老师牛牛弄不清学生们都是哪个班级的,他只能随便找两个同学,问他们是不是一个班的,牛牛记下了属于同一个班的学生的序号,但是他弄不清自己教的班级的情况,请你帮助他。
假设体育老师的学生有n人,学号分别是1,2,...n,他的小本本记录了m行,每行记下了属于一个班级的两个同学的学号u, v.
请问他的学生一共属于几个班级?人数最多的班级有几个人?
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int fa[N],flag[N];
map<int,int> me;//map里前一个数存储根节点序号,后一个数存储当前人数
int find(int n)//查询根节点
{
if(n!=fa[n])fa[n]=find(fa[n]);//路径压缩
return fa[n];
}
bool cmp(pair<int,int>a,pair<int,int>b)//按人数降序排列
{
return a.second>b.second;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
int n,m,cla=0;
cin>>n>>m;
for(int i=1;i<=n;i++)fa[i]=i;
while(m--)
{
int u,v;
cin>>u>>v;
if(find(u)!=find(v))fa[find(u)]=find(v);//这里建树时要格外注意,当两者已经有同一个根节点时不用将两点连接
}
for(int i=1;i<=n;i++)
{
if(!flag[find(i)])
{
me[find(i)]=1;
flag[find(i)]=1;
cla++;
}
else{
me[find(i)]++;
}
}
vector< pair<int,int> > ve(me.begin(),me.end());//map自定义排序需要借助pair
sort(ve.begin(),ve.end(),cmp);
cout<<cla<<' '<<ve[0].second;
}
后来发现可以用一个数组对每个集合的元素个数进行维护qwq,于是有了以下代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int fa[N],cnt[N];
int find(int n)
{
if(n!=fa[n])fa[n]=find(fa[n]);
return fa[n];
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
int n,m,cla;
cin>>n>>m;cla=n;
for(int i=1;i<=n;i++)fa[i]=i,cnt[i]=1;
while(m--)
{
int u,v;
cin>>u>>v;
if(find(u)!=find(v))
{
cla--;
cnt[find(v)]+=cnt[find(u)];
fa[find(u)]=find(v);
}
}
int ma=0;
for(int i=1;i<=n;i++)
{
ma=max(ma,cnt[find(i)]);
}
cout<<cla<<' '<<ma;
}