(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:

K​i​​: h​i​​[1] h​i​​[2] ... h​i​​[K​i​​]

where K​i​​ (>0) is the number of hobbies, and h​i​​[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;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值