题意
输入n个人的爱好,爱好相同的在同一个社交圈,跟书上的好朋友一样,如果A、B都喜欢活动1,B、C都喜欢活动2,A和B在同一圈,B和C在同一圈,则A和C也在同一圈。
思路:
跟书上一样,书上直接给出朋友关系,本题需要先依靠hobby[]来判断是否在同一个集合,还有就是书上是直接用bool数组判断是根节点的个数,本题更进一步,需要求出每个集合中的元素个数。
AC代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1100;
int father[N]; //存放父亲结点
int hobby[N]={0}; //hobby[h]为任何一个喜欢活动h的人的编号
int isRoot[N]={0};
int findFather(int x){ //查找x所在集合的根结点
if(x==father[x]) return x;
else return findFather(father[x]);
}
void Union(int a,int b){ //合并a和b所在的集合
int faA=findFather(a);
int faB=findFather(b);
if(faA!=faB){
father[faA]=faB;
}
}
int cmp(int a,int b){
return a>b;
}
void init(int n){ //初始化集合father[i]=i,且flag[i]=false
for(int i=1;i<=n;i++){
father[i]=i;
}
}
int main(){
int n,k,h;
scanf("%d",&n); //人数
init(n); //初始化
for(int i=1;i<=n;i++){
scanf("%d:",&k); //第i个人喜欢的活动个数k
for(int j=0;j<k;j++){
scanf("%d",&h); //输入第i个人喜欢的活动h
if(hobby[h]==0){ //如果活动h第一次有人喜欢
hobby[h]=i; //令i喜欢h ,hobby[i]=i,father[i]=i,所以hobby[h]=i=father[i]即为活动h的根节点
}
Union(i,findFather(hobby[h])); //合并i跟hobby[h]的集合
}
}
for(int i=1;i<=n;i++){
isRoot[findFather(i)]++; //i的根节点是findFather(i),人数+1
}
int ans=0;
for(int i=1;i<=n;i++){
if(isRoot[i]!=0) ans++;
}
printf("%d\n",ans);
sort(isRoot+1,isRoot+1+n,cmp);
for(int i=1;i<=ans;i++){
printf("%d",isRoot[i]);
if(i<ans) printf(" ");
}
return 0;
}
tips:
其实hobby[h]=i那边我不太懂,我个人的理解是把活动h的根节点设定为i。如果有大佬看了觉得我这个理解不对,可以评论一下,感谢。