【PAT甲级题解记录】1107 Social Clusters (30 分)
前言
Problem:1107 Social Clusters (30 分)
Tags:并查集
Difficulty:
剧情模式想流点汗想流点血死而无憾Address:1107 Social Clusters
题目描述
有N个人,每个人都有一个或者多个爱好,爱好用整数1-1000标记,有共同爱好的人可以被分到一个集合,求各个集合的人数。
解题思路
看到这道题不难发现其实就是并查集裸题➕求每个集合大小,加一个hobby->people的映射,在输入时检查是否有同样爱好的people,有的话再看两人是否在同个集合,是就合并。(如果这个爱好第一次出现记得更新映射数组)
至于集合的大小,可以直接开一个N大小的数组,表示每个人所在集合的大小,初始化都是1。合并时将root1的值加到root2中。不过要注意:这个数组只能给最终的root使用,其他的值都是不准确的。
参考代码
//
// Created by WU on 2023/3/2.
//
#include<bits/stdc++.h>
using namespace std;
int N;
vector<int> pre;
vector<int> h_to_p(1010, 0); // 爱好到人的映射
vector<int> num_of_set(1010, 1); // 所在集合的人数,只有集合的根才能保证该数据有效。
int find(int a) {
// if (pre[a] == a) {
// return a;
// } else {
// return pre[a] = find(pre[a]);
// }
return pre[a] == a ? a : pre[a] = find(pre[a]);
}
int combine(int a, int b) {
int pre_a = find(a);
int pre_b = find(b);
if (pre_a == pre_b) return 0;
pre[pre_a] = pre_b;
num_of_set[pre_b] += num_of_set[pre_a];
return 1;
}
void init() {
cin >> N;
pre.resize(N + 1);
for (int i = 1; i <= N; ++i) {
pre[i] = i;
}
for (int i = 1; i <= N; ++i) {
int k;
cin >> k;
getchar();
for (int j = 0; j < k; ++j) {
int h;
cin >> h;
if (h_to_p[h]) { // 该爱好出现过
if (find(i) != find(h_to_p[h])) {
combine(i, h_to_p[h]); // 如果一样爱好h的人和i不在一个集合,则合并
}
continue;
}
h_to_p[h] = i;
}
}
}
bool cmp(const int &a, const int &b) {
return a > b;
}
int main() {
init();
vector<int> ans;
for (int i = 1; i <= N; ++i) {
if (find(i) == i) {
ans.emplace_back(num_of_set[i]);
}
}
cout << int(ans.size()) << endl;
sort(ans.begin(), ans.end(), cmp);
for (int i = 0; i < int(ans.size()); ++i) {
cout << (i == 0 ? "" : " ") << ans[i];
}
cout << endl;
return 0;
}