(PAT)1107 Social Clusters (并查集)

忘是亡心i 2022-04-17 03:15 290阅读 0赞

When register on a social network, you are always asked to specify your hobbies in order to find some potential friends with the same hobbies. A social cluster is a set of people who have some of their hobbies in common. You are supposed to find all the clusters.

Input Specification:

Each input file contains one test case. For each test case, the first line contains a positive integer N (≤1000), the total number of people in a social network. Hence the people are numbered from 1 to N. Then N lines follow, each gives the hobby list of a person in the format:

Ki: hi[1] hi[2] … hi[Ki]

where Ki (>0) is the number of hobbies, and hi[j] is the index of the j-th hobby, which is an integer in [1, 1000].

Output Specification:

For each case, print in one line the total number of clusters in the network. Then in the second line, print the numbers of people in the clusters in non-increasing order. The numbers must be separated by exactly one space, and there must be no extra space at the end of the line.

Sample Input:

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

Sample Output:

  1. 3
  2. 4 3 1

解题思路:这题考察了并查集的使用

首先我们创建一个并查集,元素且根节点为人员编号,初始化的时候让各人员编号的父指针指向他自己

然后我们定义一个数组,让对应的爱好指向第一次选择这个爱号的人员编号

比如第一个人的爱好是2 7 10,那么对应的人员编号都是1

如果第二次出现了这个爱好,就让选择这个爱好的人作为第一次选这个爱好的人的子节点,插入到并查集中

最后统计并查集个数即可

1号喜欢2,7,10

2号喜欢4

3号喜欢5,3

它们之间没有共同喜欢的活动,因此分属三个不同的社交网络

4号喜欢4,所以和2同属一个网络

5号喜欢3,所以和3同属一个网络

代码:

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <vector>
  4. using namespace std;
  5. const int maxn = 1010;
  6. int course[maxn] = { 0 };
  7. int isroot[maxn] = { 0 };
  8. bool dugroot[maxn] = { 0 };
  9. class DDJSSet {
  10. private:
  11. int* father; //用来保存每个结点的父结点
  12. int* rank; //用来保存每个结点的秩
  13. public:
  14. DDJSSet(int size) {
  15. father = new int[size+1];
  16. rank = new int[size+1];
  17. for (int i = 1; i <= size; ++i) {
  18. father[i] = i; //初始化时,将每个结点的父节点指向它自己
  19. rank[i] = 0;
  20. }
  21. }
  22. ~DDJSSet() {
  23. delete[] father;
  24. delete[] rank;
  25. }
  26. int find_set(int node) {
  27. if (father[node] != node) {
  28. father[node] = find_set(father[node]);
  29. }
  30. return father[node];
  31. }
  32. void merge(int node1, int node2) {
  33. int ancestor1 = find_set(node1);
  34. int ancestor2 = find_set(node2);
  35. if (ancestor1 != ancestor2) { //如果不享有同一个公共结点的话
  36. if (rank[ancestor1] > rank[ancestor2]) { //将秩较小的结点指向秩较大的结点
  37. swap(ancestor1, ancestor2); //交换两个节点
  38. }
  39. father[ancestor1] = ancestor2; //将秩较小的结点指向秩较大的结点
  40. rank[ancestor2] = max(rank[ancestor2], rank[ancestor1] + 1);
  41. }
  42. }
  43. };
  44. bool cmp(int a, int b) {
  45. return a > b;
  46. }
  47. int main() {
  48. DDJSSet dsu(maxn);
  49. vector<int> res;
  50. int n;
  51. cin >> n;
  52. for (int i = 1; i <= n; ++i) { //一共有8个人
  53. int h = 0;
  54. scanf("%d:", &h);
  55. for (int j = 0; j < h; ++j) {
  56. int h = 0;
  57. scanf("%d", &h);
  58. if (course[h] == 0) {
  59. course[h] = i;
  60. }
  61. dsu.merge(i, dsu.find_set(course[h]));
  62. }
  63. }
  64. for (int i = 1; i <= n; ++i) {
  65. int flag = dsu.find_set(i);
  66. dugroot[flag] = true;
  67. isroot[flag]++;
  68. }
  69. int ans = 0;
  70. for (int i = 1; i <= n; ++i) {
  71. if (dugroot[i]) {
  72. ans++;
  73. res.push_back(isroot[i]);
  74. }
  75. }
  76. cout << ans << endl;
  77. sort(res.begin(), res.end(), cmp);
  78. for (auto k = 0; k < res.size(); ++k) {
  79. if (k == res.size() - 1) {
  80. cout << res[k];
  81. }
  82. else {
  83. cout << res[k] << " ";
  84. }
  85. }
  86. return 0;
  87. }

发表评论

表情:
评论列表 (有 0 条评论,290人围观)

还没有评论,来说两句吧...

相关阅读