HDU 1856 More is better (数据结构,并查集)

19 篇文章 0 订阅
6 篇文章 0 订阅

http://acm.hdu.edu.cn/showproblem.php?pid=1856


More is better

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 327680/102400 K (Java/Others)
Total Submission(s): 11695    Accepted Submission(s): 4332


Problem Description
Mr Wang wants some boys to help him with a project. Because the project is rather complex,  the more boys come, the better it will be. Of course there are certain requirements.

Mr Wang selected a room big enough to hold the boys. The boy who are not been chosen has to leave the room immediately. There are 10000000 boys in the room numbered from 1 to 10000000 at the very beginning. After Mr Wang's selection any two of them who are still in this room should be friends (direct or indirect), or there is only one boy left. Given all the direct friend-pairs, you should decide the best way.
 

Input
The first line of the input contains an integer n (0 ≤ n ≤ 100 000) - the number of direct friend-pairs. The following n lines each contains a pair of numbers A and B separated by a single space that suggests A and B are direct friends. (A ≠ B, 1 ≤ A, B ≤ 10000000)
 

Output
The output in one line contains exactly one integer equals to the maximum number of boys Mr Wang may keep. 
 

Sample Input
  
  
4 1 2 3 4 5 6 1 6 4 1 2 3 4 5 6 7 8
 

Sample Output
  
  
4 2
Hint
A and B are friends(direct or indirect), B and C are friends(direct or indirect), then A and C are also friends(indirect). In the first sample {1,2,5,6} is the result. In the second sample {1,2},{3,4},{5,6},{7,8} are four kinds of answers.
 

Author
lxlcrystal@TJU
 

Source
 


10000000壮丁(下标1 to 10000000),要抓一些壮丁出来,抓出来的壮丁必须直接或间接有联系,求最多能抓多少壮丁。

第二次做这题,发现这作为学习并查集的例题实在是太合适了


Q:什么是并查集?

A:并查集是一种用来管理元素分组情况的数据结构。并查集可以高效地进行查询和合并。


Q:并查集是用什么结构的呀?

A:树形结构,不过不是二叉树。


对于本题,我们将有直接或间接联系的放入同一棵树(使他们具有相同的根)并更新树的大小,同时记录最大树的规模。


如样例1:

4

1 2

3 4

5 6

1 6

首先初始化,每个结点都是根结点(a[i]=i,a[i]记录结点i的父结点)

读入1 2时,我们先查询1 2是否位于同一颗树内(根结点是否相同),发现根结点不同,建立树1-2(前者为根结点);

读入3 4时,同理,建立树3-4;

读入5 6时,同理,建立树5-6;

读入1 6时,我们发现1的根结点为1,6的根节点为5,建立树1-5,

则这颗树变为1-(2,5-6),规模为4。


Q:如何查询根结点?

A:用递归,直到a[i]=i时。


Q:如何合并两个结点?

A:将一个结点的父结点连到另一个结点的父结点。


关于优化:

如果将这棵树的高度减小,就能减少递归次数,从而缩短查根时间。

方法:

1.合并时,高度较小的树并入高度较大的树(需要开一个数组记录高度);

2.通过路径压缩——对于每个结点,一旦走到一次根结点,将其父结点直接改为根结点。

如果加入这两个优化,并查集的效率非常高,复杂度为阿克曼函数的反函数比O(log(n))还要快。

对于本题,由于内存限制,我们无法开一个数组记录高度,所以这优化就偷懒不做了。


#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<ctime>
#include<cctype>
#include<cmath>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#define sqr(x) (x)*(x)
#define INF 0x1f1f1f1f
#define PI 3.1415926535
#define LL long long
#define mm 10000001

using namespace std;

int a[mm],sizetree[mm],ans;			//a记录父结点,sizetree记录数的规模 
int n;

void init()
{
	for (int i=0;i<mm;i++)
	{
		a[i]=i;
		sizetree[i]=1;
	}
	
}

int root(int child)					//递归查询根结点 
{
	if (a[child]==child)
		return child;
	else
		return a[child]=root(a[child]);	//优化,直接连根结点 
	
}

void intree(int x,int y)
{
	int rx,ry;
	rx=root(x);
	ry=root(y);
	if (rx!=a[x])
		a[x]=rx;
	a[ry]=rx;
	if (ry!=rx)
		sizetree[rx]+=sizetree[ry];
	ans=max(ans,sizetree[rx]);
}

int main()
{
	
	while(scanf("%d",&n)!=EOF)
	{
		init();
		ans=1;							//注意当n=0时输出1 
		for (int i=0;i<n;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			intree(x,y);
			
		}
		printf("%d\n",ans);
	}
	
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值