(PAT)1107 Social Clusters (並查集)
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:
8
3: 2 7 10
1: 4
2: 5 3
1: 4
1: 3
1: 4
4: 6 8 1 5
1: 4
Sample Output:
3
4 3 1
解題思路:這題考察了並查集的使用
首先我們建立一個並查集,元素且根節點為人員編號,初始化的時候讓各人員編號的父指標指向他自己
然後我們定義一個數組,讓對應的愛好指向第一次選擇這個愛號的人員編號
比如第一個人的愛好是2 7 10,那麼對應的人員編號都是1
如果第二次出現了這個愛好,就讓選擇這個愛好的人作為第一次選這個愛好的人的子節點,插入到並查集中
最後統計並查集個數即可
1號喜歡2,7,10
2號喜歡4
3號喜歡5,3
它們之間沒有共同喜歡的活動,因此分屬三個不同的社交網路
4號喜歡4,所以和2同屬一個網路
5號喜歡3,所以和3同屬一個網路
程式碼:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 1010;
int course[maxn] = { 0 };
int isroot[maxn] = { 0 };
bool dugroot[maxn] = { 0 };
class DDJSSet {
private:
int* father; //用來儲存每個結點的父結點
int* rank; //用來儲存每個結點的秩
public:
DDJSSet(int size) {
father = new int[size+1];
rank = new int[size+1];
for (int i = 1; i <= size; ++i) {
father[i] = i; //初始化時,將每個結點的父節點指向它自己
rank[i] = 0;
}
}
~DDJSSet() {
delete[] father;
delete[] rank;
}
int find_set(int node) {
if (father[node] != node) {
father[node] = find_set(father[node]);
}
return father[node];
}
void merge(int node1, int node2) {
int ancestor1 = find_set(node1);
int ancestor2 = find_set(node2);
if (ancestor1 != ancestor2) { //如果不享有同一個公共結點的話
if (rank[ancestor1] > rank[ancestor2]) { //將秩較小的結點指向秩較大的結點
swap(ancestor1, ancestor2); //交換兩個節點
}
father[ancestor1] = ancestor2; //將秩較小的結點指向秩較大的結點
rank[ancestor2] = max(rank[ancestor2], rank[ancestor1] + 1);
}
}
};
bool cmp(int a, int b) {
return a > b;
}
int main() {
DDJSSet dsu(maxn);
vector<int> res;
int n;
cin >> n;
for (int i = 1; i <= n; ++i) { //一共有8個人
int h = 0;
scanf("%d:", &h);
for (int j = 0; j < h; ++j) {
int h = 0;
scanf("%d", &h);
if (course[h] == 0) {
course[h] = i;
}
dsu.merge(i, dsu.find_set(course[h]));
}
}
for (int i = 1; i <= n; ++i) {
int flag = dsu.find_set(i);
dugroot[flag] = true;
isroot[flag]++;
}
int ans = 0;
for (int i = 1; i <= n; ++i) {
if (dugroot[i]) {
ans++;
res.push_back(isroot[i]);
}
}
cout << ans << endl;
sort(res.begin(), res.end(), cmp);
for (auto k = 0; k < res.size(); ++k) {
if (k == res.size() - 1) {
cout << res[k];
}
else {
cout << res[k] << " ";
}
}
return 0;
}