题目: 在一个社区里,每个人都有自己的小圈子,还可能同时属于很多不同的朋友圈。我们认为朋友的朋友都算在一个部落里,于是要请你统计一下,在一个给定社区中,到底有多少个互不相交的部落?并且检查任意两个人是否属于同一个部落。
输入样例:
4
3 10 1 2
2 3 4
4 1 5 7 8
3 9 6 4
2
10 5
3 7
输出样例:
10 2
Y
N
题目分析:应用并查集。因为题目要求输出社区总人数以及有几个部落(也就是有几个根节点),可以应用set容器解。
关于并查集和set集合的知识点理解 : 传送门
嗯…对于我这个小白这道题正好练习并查集和set容器了…首先这个输入不是n个朋友圈嘛,然后每行输入第 i 个朋友圈里的人的编号。那就把第一个人当成根节点,然后之后的人直接Join进去,这个Join函数,最后谁做根节点不要紧,形成一个部落才是目标。之后放个迭代器,把根节点的所在编号放到另一个set容器里,set容器相当于一个集合,会自动删去重复项,之后对其进行s.size()就可以得到有多少个部落了。
#include<iostream>
#include<set>
using namespace std;
int pre[10005];//存放根节点
int init(){ //初始化pre数组
for(int i=0;i<10005;i++){
pre[i]=i;
}
}
int Find(int x){ //找根节点
int r=x;
while(r!=pre[r]){
r=pre[r];
}
int i=x,j;
while(pre[i]!=r)//路径压缩
{
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
int Join(int x,int y){ //朋友圈扩大~
int fx=Find(x);
int fy=Find(y);
if(fy!=fx){
pre[fy]=fx;
}
}
int main(){
init();
set<int> s;
set<int> cs; //创建俩容器
int n,k;
int p;
int m,d;
cin>>n;
for(int i=0;i!=n;i++){
cin>>k;
cin>>m;//把该朋友圈的第一个人的编号树当做头结点
s.insert(m);
for(int j=1;j!=k;j++){
cin>>d;
s.insert(d);
Join(m,d);
}
}
set<int>::iterator iter; //创建迭代器
for(iter=s.begin();iter!=s.end();++iter){
cs.insert(Find(*iter));
}
cout<<s.size()<<" "<<cs.size()<<endl;
int q;
cin>>q;
while(q--){
int m,n;
cin>>m>>n;
if(Find(m)!=Find(n)) cout<<"N"<<endl;
else cout<<"Y"<<endl;
}
}