【C】并查集

1107. Social Clusters (30)

时间限制
1000 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

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

#include<stdio.h>
#include<algorithm>
using namespace std;
int hobbyfather[1010]={0};
int father[1010];
int n;
bool cmp(int a,int b){
	return a>b;
}
void initial(){
	int i;
	for(i=1;i<=n;i++){
		father[i]=i;
	}
}
int findfather(int a){
	int x=a;
	while(a!=father[a]){
		a=father[a];
	}
	while(x!=father[x]){
		int z=x;
		x=father[x];
		father[z]=a;
	}
	return a;
}
void UNION(int a,int b){
	int fa=findfather(a);
	int fb=findfather(b);
	if(fa!=fb){
		father[fb]=fa;
	}
}
int main(){
	scanf("%d",&n);
	int i,j;
	int num[1010]={0};
	initial();
	for(i=1;i<=n;i++){
		int b;
		scanf("%d: ",&b);
		for(j=1;j<=b;j++){
			int c;
			scanf("%d",&c);
			if(hobbyfather[c]!=0){//已经有hobbyfather[c]提及了这个hobby,将hobbyfather[c]与这个i合并
				UNION(i,findfather(hobbyfather[c]));
				//num[findfather(i)]++;
			}
			else{//这个hobby之前没有被提及
				hobbyfather[c]=i;
				//num[findfather(i)]++;
			}
		}
	}
	for(i=1;i<=n;i++){
		num[findfather(i)]++;
	}
	sort(num+1,num+n+1,cmp);
	for(i=1;i<=n;i++){
		if(num[i]==0) break;
	}
	printf("%d\n",i-1);
	for(j=1;j<i-1;j++){
		printf("%d ",num[j]);
	}
	printf("%d",num[i-1]);
	return 0;
}

找朋友:即找有相同的朋友的团体

#include<stdio.h>
int father[110];
int n;
void initial(){
	int i;
	for(i=1;i<=n;i++){
		father[i]=i;
	}
}
int findfather(int a){
	int x=a;
	while(a!=father[a]){
		a=father[a];
	}//a是x的根
	//以下缩短路径
	while(x!=father[x]){
		int z=x;
		father[x]=a;//该路径上的元素根都改为a
		x=father[z];//寻找下一个
	}
	return a;
}
void UNION(int a,int b){//若a,b所在不同集合,合并
	int fa=findfather(a);
	int fb=findfather(b);
	if(fa!=fb){
		father[fa]=fb;//注意这里合并是根的合并
	}
}
int main(){
	int m,num=0,i;
	scanf("%d %d",&n,&m);
	initial();
	for(i=0;i<m;i++){
		int a,b;
		scanf("%d %d",&a,&b);
		UNION(a,b);
	}
	for(i=1;i<=n;i++){
		if(father[i]==i) num++;
	}
	printf("%d",num);
	return 0;
}

问题 A: 通信系统

时间限制: 1 Sec   内存限制: 32 MB
提交: 152   解决: 51
[ 提交][ 状态][ TK题库][命题人: ]

题目描述

某市计划建设一个通信系统。按照规划,这个系统包含若干端点,这些端点由通信线缆链接。消息可以在任何一个端点产生,并且只能通过线缆传送。每个端点接收消息后会将消息传送到与其相连的端点,除了那个消息发送过来的端点。如果某个端点是产生消息的端点,那么消息将被传送到与其相连的每一个端点。
为了提高传送效率和节约资源,要求当消息在某个端点生成后,其余各个端点均能接收到消息,并且每个端点均不会重复收到消息。
现给你通信系统的描述,你能判断此系统是否符合以上要求吗?

输入

输入包含多组测试数据。每两组输入数据之间由空行分隔。
每组输入首先包含2个整数N和M,N(1<=N<=1000)表示端点个数,M(0<=M<=N*(N-1)/2)表示通信线路个数。
接下来M行每行输入2个整数A和B(1<=A,B<=N),表示端点A和B由一条通信线缆相连。两个端点之间至多由一条线缆直接相连,并且没有将某个端点与其自己相连的线缆。
当N和M都为0时,输入结束。

输出

对于每组输入,如果所给的系统描述符合题目要求,则输出Yes,否则输出No。

样例输入

4 3
1 2
2 3
3 4

3 1
2 3

0 0

样例输出

Yes
No

#include<stdio.h>
int father[1010];
int n;
void initial(){
	int i=0;
	for(i=1;i<=n;i++){
		father[i]=i;
	}
}
int findfather(int a){
	int x=a;
	while(a!=father[a]){
		a=father[a];
	}
	while(x!=father[a]){
		int z=x;
		x=father[x];
		father[z]=a;
	}
	return a;
}
void UNION(int a,int b){
	int fa=findfather(a);
	int fb=findfather(b);
	if(fa!=fb) father[fa]=fb;
}
int main(){
	int i,m,num=0;
	scanf("%d %d",&n,&m);
	while(n!=0||m!=0){//这个判断条件要注意,不是&&,因为m可以为0
		initial();//不仅不能忘记initial更不能忘记先scanf&n,再initial!!!
		for(i=0;i<m;i++){
			int a,b;
			scanf("%d %d",&a,&b);
			UNION(a,b);
		}
		for(i=1;i<=n;i++){
			if(father[i]==i) num++;
		}
		if(num==1) printf("Yes\n");
		else printf("No\n");
		scanf("%d %d",&n,&m);
	}
	return 0;
}
	

问题 B: 畅通工程

时间限制: 1 Sec   内存限制: 32 MB
提交: 61   解决: 35
[ 提交][ 状态][ TK题库][命题人: ]

题目描述

某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?

输入

测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出一对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。 
    注意:两个城市之间可以有多条道路相通,也就是说
    3 3
    1 2
    1 2
    2 1
    这种输入也是合法的
    当N为0时,输入结束,该用例不被处理。

输出

对每个测试用例,在1行里输出最少还需要建设的道路数目。

样例输入

5 3
1 2
3 2
4 5
0

样例输出

1
//有n个集合,就需要再建n-1条路
#include<stdio.h>
int father[1010];
int n;
void initial(){
	int i;
	for(i=1;i<=n;i++){
		father[i]=i;
	}
}
int findfather(int a){
	int x=a;
	while(a!=father[a]){
		a=father[a];
	}
	while(x!=father[a]){
		int z=x;
		x=father[z];
		father[z]=a;
	}
	return a;
}
void UNION(int a,int b){
	int fa=findfather(a);
	int fb=findfather(b);
	if(fa!=fb) father[fa]=fb;
}
int main(){
	int i,j,m;
	scanf("%d %d",&n,&m);
	while(n!=0){
		initial();
		int num=0;
		for(j=0;j<m;j++){
			int a,b;
			scanf("%d %d",&a,&b);
			UNION(a,b);
		}
		for(i=1;i<=n;i++){
			if(father[i]==i) num++;
		}
		printf("%d\n",num-1);
		scanf("%d %d",&n,&m);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值