在社交网络平台注册时,用户通常会输入自己的兴趣爱好,以便找到和自己兴趣相投的朋友。有部分兴趣相同的人们就形成了“社交集群”。现请你编写程序,找出所有的集群。
输入格式:
输入的第一行给出正整数N(<=1000),即社交网络中的用户总数(则用户从1到N编号)。随后N行,每行按下列格式列出每个人的兴趣爱好: Ki: hi[1] hi[2] … hi[Ki] 其中Ki(>0)是第i个人的兴趣的数量,hi[j]是第i个人的第j项兴趣的编号,编号范围为[1, 1000]内的整数。
输出格式:
首先在第一行输出整个网络中集群的数量,然后在第二行按非递增的顺序输出每个集群中用户的数量。数字间以1个空格分隔,行首尾不得有多余空格。
输入样例:
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
把存在相同爱好的人归为一个群,如上面的例子,2、4、6、8是一个集群,3、5、7是一个集群,1是一个集群,这里的数字是每个人的编号,由此可以得到存在三个集群,且数量分别是4 3 1。 从题中可以看出,这个题目可以用并查集求解。 init_father、find_father和union_father函数分别是并查集的三个基本操作,不理解并查集的可以看维基百科-并查集,这里我用了较多的容器,是为了方便求解,set是为了快速判断两个人是否存在相同的兴趣点,map是为了统计有几个社交集群,priority_queue是为了按非递增顺序输出社交集群的数量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| #include <cstdio> #include <vector> #include <set> #include <iterator> #include <functional> #include <map> #include <queue>
using namespace std;
int *father;
void init_father(int n) { father = new int[n + 1]; for (int i = 0; i <= n; i++) father[i] = i; }
int find_father(int x) { if (father[x] == x) return x; return find_father(father[x]); }
void union_father(int arg1, int arg2) { int fa = find_father(arg1); int fb = find_father(arg2); father[fa] = fb; }
int main() { int n = 0, ki = 0, hobby = 0; scanf("%d", &n); init_father(n); vector<set<int> > hobbies(n + 1); for (int i = 1; i <= n; i++) { scanf("%d:", &ki); for (int j = 0; j < ki; j++) { scanf("%d", &hobby); hobbies[i].insert(hobby); for (int k = 1; k < i; k++) { if (hobbies[k].find(hobby) != hobbies[k].end()) { union_father(i, k); } } } }
map<int, int> m; for (int i = 1; i <= n; i++) { m[find_father(i)]++; } printf("%ld\n", m.size());
priority_queue<int, vector<int>, less<int>> q; for (auto it = m.begin(); it != m.end(); it++) { q.push(it->second); } while (q.size() > 1) { printf("%d ", q.top()); q.pop(); } printf("%d", q.top()); return 0; }
|