1107 Social Clusters (30分)

题目链接:1107 Social Clusters

题意:

给出N个人的爱好种类,爱好相同的人为一个群体。成为一个群体的条件与群体中的某个人有一个相同的爱好,输出群体个数,和每个群体的人数。

题解:

考察并查集。每个人的爱好种类都自成一个集合,若自己的爱好中有属于其他人集合的,则将两个人的爱好合并为一个集合。设这个集合的根结点的值为群体的人数负值。
设f[maxn]为爱好的集合,f[i] = a,若a为正整数代表i属于集合a;为0代表没有出现这个爱好;负数表示,i为根结点,且这个集合的人数为-a.
输入时将每个的第一个爱好当做这个集合的根节点,第一个爱好的父节点设为rf,将rf所在的集合减1,表示这个集合的人数加一。后面的每个集合全部并入第一个爱好的集合中,并入后更新集合的人数。最后遍历f数组查询有多少个负值就代表有多少个群体,将负值变正存到结果数组中,最后排序输出。

代码:

#include
#include
#include
#include
/* run this program using the console pauser or add your own getch, system(“pause”) or input loop */

using namespace std;
const int maxn = 1010;
int f[maxn] = {0};
int findRoot(int x);
void Union(int a, int b);
bool cmp(int a, int b) {
return a > b;
}
int main(int argc, char** argv) {

int n, k, x, r;
int group[maxn] = {0};
scanf("%d", &n);
while (n--) {
	scanf("%d", &k);
	getchar();
	scanf("%d", &r);
	int rf = findRoot(r); // 第一个爱好的父节点
    f[rf]--; // 只在第一个爱好中减,表示这个集合增加一个人
	for (int i = 1; i < k; i++) { // 将后面的所有关系并入r中
		scanf("%d", &x);
		int t = findRoot(x);
		if (t != rf) // 与第一个爱好不在一个集合,则并入第一个爱好的集合
			Union(t, rf);
	}
}
int sum = 0;
for (int i = 1; i < maxn; i++) {
	if (f[i] < 0)
		group[sum++] = -f[i];
}
sort(group, group + sum, cmp);
printf("%d\n", sum);
for (int i = 0; i < sum; i++) {
	if (i != sum - 1)
		printf("%d ", group[i]);
	else
		printf("%d\n", group[i]);
}
return 0;

}
int findRoot(int x) {
int a = x;
while (f[x] > 0) {
x = f[x];
}
int father = x;
// 压缩路径
while (f[a] > 0) {
int t = a; // !!
a = f[a];
f[t] = father;
}
return father;
}
/**
将a的集合并到b中,并更新b的集合元素个数
*/
void Union(int a, int b) {
int cnt = f[a];
f[a] = b;
f[b] += cnt;
}

发布了17 篇原创文章 · 获赞 0 · 访问量 456

猜你喜欢

转载自blog.csdn.net/qq_37866436/article/details/104181297