团体天梯练习 L3-003 社交集群

题目

题目描述

当你在社交网络平台注册时,一般总是被要求填写你的个人兴趣爱好,以便找到具有相同兴趣爱好的潜在的朋友。一个“社交集群”是指部分兴趣爱好相同的人的集合。你需要找出所有的社交集群。

输入格式

输入在第一行给出一个正整数 \(N\) \((\le 1000)\),为社交网络平台注册的所有用户的人数。于是这些人从 \(1\)\(N\) 编号。 随后 \(N\) 行,每行按以下格式给出一个人的兴趣爱好列表:

\(K_i\) : \(h_i[1]\) \(h_i[2]\) \(\ldots\) \(h_i[K_i]\)

其中 \(K_i\) \((>0)\) 是兴趣爱好的个数,\(h_i[j]\) 是第 \(j\) 个兴趣爱好的编号,为区间 \([1, 1000]\) 内的整数。

输出格式

首先在一行中输出不同的社交集群的个数。随后第二行按非增序输出每个集群中的人数。数字间以一个空格分隔,行末不得有多余空格。

输入样例

8
3: 2 7 10
1: 4
2: 5 3
1: 4
1: 3
1: 4
4: 6 8 1 5
1: 4

输出样例

3
4 3 1

思路

一个“社交集群”是指部分兴趣爱好相同的人的集合,我们可以将每个爱好对应的人都存起来。之后,枚举每个爱好,采用并查集将对应序列中所有人进行合并(维护一下集合大小),总合并次数不会超过 \(10^6\)。最后按要求输出每个集合大小即可。


代码

#include<bits/stdc++.h>
using namespace std;

#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 1010;

int num;
unordered_map<int, int> mp;

inline int getid(int x){ return mp.count(x) ? mp[x] : mp[x] = ++ num; }

vector<int> v[N]; // 存储每个爱好的人
char ch;
int n, fa[N], sz[N];

inline int find(int x){ return fa[x] == x ? x : fa[x] = find(fa[x]); }
inline void merge(int x, int y){
    int fx = find(x), fy = find(y);
    if(fx ^ fy) fa[fx] = fy, sz[fy] += sz[fx];
}

int main(){
    ios;

    cin >> n;
    for(int i = 1, k; i <= n; i ++ ){
        cin >> k >> ch;
        for(int j = 1, x; j <= k; j ++ ){
            cin >> x;
            x = getid(x);
            v[x].push_back(i);
        }
    }

    for(int i = 1; i <= n; i ++ ) fa[i] = i, sz[i] = 1;
    for(int i = 1; i <= num; i ++ ){
        int f = find(v[i][0]);
        for(int j = 1; j < (int)v[i].size(); j ++ ) merge(f, v[i][j]);
    }

    vector<int> ans;
    for(int i = 1; i <= n; i ++ ) if(fa[i] == i) ans.push_back(sz[i]);
    sort(begin(ans), end(ans), greater<int>());
    cout << ans.size() << "\n";
    for(int i = 0; i < (int)ans.size(); i ++ ) cout << ans[i] << " \n"[i == (int)ans.size() - 1];

    return 0;
}

posted @ 2023-04-21 23:08  MarisaMagic  阅读(88)  评论(0编辑  收藏  举报