1107 Social Clusters (30 分)
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
set[i] 的下标为爱好(数组范围可以看到1001) 并不是人 (并查集 数组范围由下标类型的数量决定, 此题的下标也可以用人的索引来表示,此时 下标的范围就为 n)
merge 所有爱好时 因为要计算人的数量, 通过 person[i]数组 记录 爱好为 i 的人数 当合并一个人的爱好时,就使此人其中一个爱好的person[i]值 ++,
当合并所有爱好后 , 通过num[i]计算出每个社交圈人数的数量
for(int i = 1; i < maxsize; i++){
if(person[i] >0){
num[find(i)] += person[i]; //将每个社交圈的人数相加
}
}
计算出社交圈的数量
int sum = 0;
for(int i = 1; i < maxsize; i++){
if(num[i] > 0){
sum++; //计算出社交圈的数量
}
}
具体代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int maxsize = 1001;
int n, set[maxsize], num[maxsize] = {0}, person[maxsize] = {0}; //person[i] = value 爱好为 i的人数为 value
bool visit[maxsize];// visit[i] = true 表示i点已经加入集合
int find(int i){
return i == set[i] ? i : set[i] = find(set[i]);
}
void merge(int a, int b){
int faA = find(a);
int faB = find(b);
if(faA != faB)
set[faA] = faB;
}
void init(){
for(int i = 1; i < maxsize; i++){
set[i] = i;
}
}
int main(){
int k, h1, hi;
scanf("%d", &n);
init();
for(int i = 1; i <= n; i++){
scanf("%d:%d", &k, &h1); //
visit[i] = true;
for(int i = 1; i < k; i++){
scanf("%d", &hi);
visit[i] = true;
merge(h1, hi);
}
person[find(h1)]++;
}
for(int i = 1; i < maxsize; i++){
if(person[i] >0){
num[find(i)] += person[i]; //将每个社交圈的人数相加
}
}
int sum = 0;
for(int i = 1; i < maxsize; i++){
if(num[i] > 0){
sum++; //计算出社交圈的数量
}
}
sort(num + 1, num + maxsize, greater<int>());
printf("%d\n", sum);
for(int i = 1; i <= sum; i++){
printf("%d", num[i]);
if(i != sum){
printf(" ");
}
}
return 0;
}
参考柳神大佬的思路2 : set[i]的 下标为 人的索引, 此时需要合并的是人, 并不是 爱好, 合并人的条件并不能 如同合并爱好直接合并
一个人相同的爱好一样 合并人1 人 2, 应该根据人具有相同的爱好来合并 因此 设定一个数组 count1[i]
当 count1[i] 为 0时 表示 爱好为i的人索引为 0 (题目中规定人的编号 为 1-n )因此表示没人拥有此爱好, 当存在了人的索引为
j (j > 0) 时 使 count1[i] = j; 此时 j 就作为有 i 爱好的人需要 连接的终点,当需要就算每个社交圈(集合)的人数时只需要判断
for(int i = 1; i <= n; i++){
num[find(set[i])]++;
}
判断社交圈(集合)的数量:
int sum = 0;
for(int i = 1; i <= n; i++){
if(num[i] > 0) sum++;
}
具体代码如下:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int n, count1[1001] = {0};
vector<int> num, set;
int find(int i){
return set[i] == i? i : set[i] = find(set[i]);
}
void merge(int a, int b){
int faA = find(a);
int faB = find(b);
if(faA != faB){
set[faA] = faB;
}
}
void init(){
for(int i = 1; i <= n; i++){
set[i] = i;
}
}
int main(){
int k, bi;
scanf("%d", &n);
num.resize(n);
set.resize(n);
init();
for(int i = 1; i <= n; i++){
scanf("%d:",&k);
for(int j = 1; j <= k; j++){
scanf("%d", &bi);
if(count1[bi] == 0) count1[bi] = i;
merge(i, find(count1[bi])); //将人i 与 第一个拥有此爱好的人find(count1[bi])合并
}
}
for(int i = 1; i <= n; i++){
num[find(set[i])]++;
}
int sum = 0;
for(int i = 1; i <= n; i++){
if(num[i] > 0) sum++;
}
sort(num.begin() + 1, num.end(), greater<int>()); //从大到小排列
printf("%d\n",sum);
for(int i = 1; i <= sum; i++){
if(i != 1)
printf(" ");
printf("%d", num[i]);
}
return 0;
}