1. 程式人生 > >(PAT)1107 Social Clusters (並查集)

(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;
}