HDU1213 How Many Tables(并查集入门)[C,C++]

题目及翻译

题面

Today is Ignatius’ birthday. He invites a lot of friends. Now it’s dinner time. Ignatius wants to know how many tables he needs at least. You have to notice that not all the friends know each other, and all the friends do not want to stay with strangers.
One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table.
For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one. So Ignatius needs 2 tables at least.
翻译
今天是Ignatius的生日,他邀请了很多朋友。晚餐时间到了,Ignatius想要知道最少要办几桌餐,你注意到并不是并不是所有人都相互认识,但是所有人都不想和不认识的人一起坐。这个问题有一个重要规则:如果A认识B,B认识C,那他们就能够坐在一起。
举个栗子:已知A认识B,B认识C,而D认识E,那么A、B、C就能坐在一桌,而D和E得一起坐在另一桌,这就需要最少2张桌子。

输入

The input starts with an integer T(1<=T<=25) which indicate the number of test cases. Then T test cases follow. Each test case starts with two integers N and M(1<=N,M<=1000). N indicates the number of friends, the friends are marked from 1 to N. Then M lines follow. Each line consists of two integers A and B(A!=B), that means friend A and friend B know each other. There will be a blank line between two cases.
翻译
首先输入一个T(1<=T<=25)表示总共有T组样例。
每组样例先输入N和M(1<=N,M<=1000)两个整数。N代表朋友的个数,从1到N编号。
然后输入M行,每行包含两个整数A和B(A和B不相等),表示A和B互相认识。
每组样例之间有一个空行。

输出

For each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks.
翻译
对于每组样例,只需要输出Ignatius最少需要的桌子数,不需要打印多余的空行。

输入样例

2
5 3
1 2
2 3
4 5

5 1
2 5

输出样例

2
4

题目思路

这就是最基础的并查集,把互相认识的人放到同一个集合然后统计集合个数即可。

注意事项

输入里说了空行,但是输出不需要!

AC代码

C/C++(几乎没有代码变更)

用时0MS 内存1220K 长度1156B

#include<stdio.h>
int t,n,m,Num1,Num2,Num[1005],setNum;
int find(int x) {//找到x的根节点 
	int tmp,son;//定义子节点,标记节点 
	son = x;//子节点为输入的节点 
	while(x!=Num[x])//如果输入节点的父节点不是本事 
		x = Num[x];//就把输入节点跳转到他的父节点,直到找到根节点 
	//此时x已经是根节点了 
	while(son!=x){//路径压缩,这题没必要,我顺便复习 
		tmp = Num[x];//标记目前的父节点 
		Num[son] = x;//子节点的父节点改为根节点 
		son = tmp;//子节点变为其原来的父节点 
	}
	return x;
}
void merage(int x,int y) {//合并两个集合 
	int fx = find(x);//寻找x的根节点 
	int fy = find(y);//寻找y的根节点 
	if(fx != fy)//如果两者不是同一个集合(根节点不同) 
		Num[fx] = fy;//就把两者合并,由于写了路径压缩所以这里不必特意优化 
	return;
}
int main() {
	scanf("%d",&t);
	while(t--) {
		scanf("%d %d",&n,&m);
		//initialize 初始化
		setNum = 0; 
		for(int i=1; i<=n; ++i)//只需要初始化到n即可
			Num[i] = i; 
		//核心代码 
		for(int i=0; i<m; ++i) {
			scanf("%d %d",&Num1,&Num2);
			merage(Num1,Num2);
		}
		for(int i=1;i<=n;++i)
			if(find(i) == i)++setNum;//如果根节点是本身,代表了一个集合 
		printf("%d\n",setNum);
	}
	return 0;
}

Java

我还没写哦寝室要断电咯!

本文作者 CSDN@扶她小藜
个人主页链接 https://blog.csdn.net/weixin_44579869

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值