PAT Advanced1107 Social Clusters(并查集)

链接:PAT Advanced1107

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



题意:

有N个人,每个人喜欢若干项活动,如果两个人有任意一个活动相同,那么称他们处于同一个社交网络(若A和B属于同一个社交网络,B和C属于同一个社交网络,那么A、B、C同属于一个社交网络)。求这N个人总共形成了多少个社交网络,并以非递增顺序输出各个社交网络的人数。



分析:

每个社交网络相当于一个集合,若A、B有任意一个活动相同,则将两个集合合并,最后遍历每个人,找出一共有多少个不同的根节点(即集合数目),同时记录各集合内的元素数量。


以下代码:

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=1010;
int father[maxn],cnt[maxn]={0};
vector<int> ans,hobby[maxn];   //hobby[h]中存储喜欢的活动为h的所有人的编号
bool cmp(int a,int b){ return a>b; }
void init(int n)      //不要忘了并查集的初始化
{
	for(int i=1;i<=n;i++)
		father[i]=i;
}
int findfather(int x)             //查找根结点
{
	int root=x;
	while(root!=father[root])     //找到根结点
		root=father[root];
		
	//路径压缩,可将查找的时间复杂度降为 O(1)
	while(x!=father[x])    //重新走一遍路径
	{                      //让路径上的所有结点直接和根结点相连
		int t=x;
		x=father[x];       //继续向上走
		father[t]=root;    //当前结点直接与根结点相连
	}
	
	return root;
}
int Union(int a,int b)     //合并集合
{
	int Fa=findfather(a);
	int Fb=findfather(b);
	if(Fa!=Fb)
		father[Fa]=Fb;
}
int main()
{	
	int N,K,h;
	scanf("%d",&N);
	init(N);
	for(int i=1;i<=N;i++)
	{
		scanf("%d%*c",&K);
		while(K--)
		{
			scanf("%d",&h);
			for(int j=0;j<hobby[h].size();j++)
				Union(i,hobby[h][j]);          //和有相同活动的人集合合并
			hobby[h].push_back(i);
		}
	}
	for(int i=1;i<=N;i++)
		cnt[findfather(i)]++;           //cnt下标为根结点编号
	for(int i=1;i<=N;i++)
	{
		if(cnt[i]!=0)                   //找到元素个数不为0集合
			ans.push_back(cnt[i]);      //存储元素个数
	}
	sort(ans.begin(),ans.end(),cmp);    //排序
	printf("%d\n",ans.size());          //输出
	for(int i=0;i<ans.size();i++)
	{
		if(i!=0)
			printf(" ");
		printf("%d",ans[i]);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值