HDU1213 How Many Tables c++

How Many Tables

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 47785 Accepted Submission(s): 23810

Problem Description
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.

Input
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.

Output
For each test case, just output how many tables Ignatius needs at least. Do NOT print any blanks.

Sample Input
2
5 3
1 2
2 3
4 5

5 1
2 5

Sample Output
2
4

问题连接

问题描述

Ignatius的生日派对要邀请很多朋友,但是朋友们都不想和陌生人待在一起,规则是:如果A认识B,并且B认识C, 那么可以认为A,C不是陌生人,而A,B,C可以坐同一张桌子。
所以任务是指出Ignatius至少需要准备多少张桌子。

问题分析

方法是:并查集。这里我直接使用以前写的要点。
要点就是:一个数组和两个函数。
一个数组friends[1001],使用下标当成friends的编号,每个元素(除0不使用)都储存着连接它们的上一个friends的编号。最终连接的friends里储存的是它自己的下标。
函数int root(int x);作用是找到下标为x的friends的最终连接的friends的下标(根节点),并且让连在一起的其它friends都改成存储最终连接的friends的下标(路径压缩)。而路径压缩的作用就在于让下次找根节点时找直接找到,减少了寻找的步骤。做法: 判断一个friends的下标和它自身的内容是否相等,如果不等就找到上一个friends的下标,用相同的方法去判断,直到相等为止(此时这个下标r就是根节点);实现路径压缩,方法和上面基本一样,主要多了同时让每个friends的内容都改成根节点r。
函数void join(int x,int y); 作用是连接两个不在同一类的群。如:{1,3,5,7,8}和{2,4,6,9}。通过这个函数把它们变为一体{1,2,3,4,5,6,7,8,9}。做法: 判断根节点是否相同,如果不同就让其中一个的根节点改成另一个的根节点。

然后就是根据题意,使用root函数和join函数了,题意给出了朋友间的关系,用join()函数处理,处理后可以得到新的friends[]数组,其中有friends[i]==i的情形和friends[i]!=i的情形。若等于i代表它就是根结点;若不等于i代表它能找到上一个结点,最后找到根结点,那么这之间的所有下标i都是联系在一起的。所以说有多少个根结点就有多少个类群,就有多少张桌子。

c++程序如下

#include<iostream>
using namespace std;
int root(int);//找到根结点以及路径压缩
void join(int, int);//建立关系
void deal(int);//负责重置
int friends[1001];
int main()
{
	int i, t, n, m, a, b, table;
	cin >> t;
	while (t--)
	{
		cin >> n >> m;
		deal(n);//重置
		while (m--)//建立关系
		{
			cin >> a >> b;
			join(a, b);
		}
		for (table = 0, i = 1; i <= n; i++)//通过判断结点是否改变来找有几个不同的集合
		{
			int rooti = root(i);
			if (rooti == i) table++;
		}
		cout << table << endl;

	}
	system("pause");
	return 0;
}
int root(int x)
{
	int r = x;
	while (r != friends[r]){ r = friends[r]; }
	int i = x, j;
	while (i != friends[i])
	{
		j = i;
		i = friends[i];
		friends[j] = r;
	}
	return r;
}
void deal(int n)
{
	for (int i = 1; i <= n; i++)
	{
		friends[i] = i;
	}
}
void join(int x, int y)
{
	int root1 = root(x), root2 = root(y);
	if (root1 != root2)
	{
		friends[root1] = root2;
	}
}

ACC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值