题目链接:PAT【甲级】1107
题目简述:有n
个人,每个人喜欢k
个活动,如果两个人有任意⼀个活动相同,就称为他们处于同一个社交网络。求这n
个人⼀共形成了多少个社交网络。
#include<bits/stdc++.h>
using namespace std;
int father[1001], exist[1001], hobby[1001];
vector<int> ans;
int findFather(int a){
int x = a;
while(x != father[x]) x = father[x];
while(a != father[a]){//压缩路径
int t = father[a];
father[a] = x;
a = t;
}
return x;
}
void Union(int a, int b){
int x1 = findFather(a), x2 = findFather(b);
father[x1] = x2;
}
int main(){
int n;
cin >> n;
for (int i = 0; i < 1001;i++)//初始化并查集
father[i] = i;
for (int i = 0; i < n;i++){
int c, t, pre;
scanf("%d:%d", &c, &pre);
exist[pre] = 1;//标记存在出现
hobby[i] = pre;//存储第i个成员的一个爱好
for (int j = 1; j < c;j++){
cin >> t;
Union(t, pre);
pre = t;
exist[t] = 1;//标记存在出现
}
}
/*代码截止到这里,并查集已经建立完成;但是各节点路径压缩并没有全部完成*/
for (int i = 0; i < n; i++)
exist[findFather(hobby[i])]++;//记录人数
for (int i = 0; i < 1001;i++)
if(exist[i] > 1)
ans.push_back(exist[i] - 1);//添加爱好相同的团体人数
sort(ans.begin(), ans.end());
cout << ans.size() << endl << ans[ans.size() - 1];
for (int i = ans.size() - 2; i >= 0; i--)
cout << " " << ans[i];
cout << endl;
return 0;
}
题目分析
拿到这个题目,就晓得是需要使用并查集的知识来解决,这样会把爱好都分成不同的团体,然后再去映射到不同的人,最后统计人数即可。
我这里是使用exist数组来充当记录的作用,因为爱好都已经分好集合了,那么我们现在开始从每个人出发,这时也就用到了之前记录的变量hobby[i]
,由于并查集的建立,这个爱好的取值可以是当前人的任意一个爱好,便于代码编写,这里选择第一个爱好。然后便去找寻其父亲,在对应位置处该爱好人数加1
。
最后输出即可。
坑点
对于
/*代码截止到这里,并查集已经建立完成;但是各节点路径压缩并没有全部完成*/
for (int i = 0; i < n; i++)
exist[findFather(hobby[i])]++;//记录人数
这部分代码,切不可写成以下样式,原因就是注释。
for (int i = 0; i < n; i++)
exist[father[hobby[i]]]++;