子树包含了多少个节点(并查集)——czy的工程VS hdoj1856 More is better

问题 H: CZY的工程

时间限制: 1 Sec   内存限制: 128 MB
提交: 74   解决: 39
[ 提交][ 状态][ 讨论版]

题目描述

CZY总是遇到这样或那样的问题,现在他又遇到了一个,CZY接到一个大的工程,想想这是走上人生巅峰的第一步啊,CZY想想就高兴,可是这个工程太大了,他需要很多人的帮助才可以,但是为了方便工作,CZY希望他的团队两人两人之间都是朋友关系,或者间接是朋友关系。毕竟是大油水的工程啊,来了一群小伙伴报名,CYZ想请聪明的你帮忙算一算,他可以招到的最大的人数是多少

输入

输入包含多组测试数据,每组测试数据第一行一个n,表示来报名的小伙伴们的编号1-100,后边接n行,每行两个整数a b,表示编号a和b的小伙伴是朋友关系

输出

输出包括一行,即CZY可以招到的最大的人数是多少

样例输入

41 23 45 61 6

样例输出

4
#include<stdio.h>
int per[1000];
int num[1000];
int find(int x)
{
	if(per[x]==x)
	return x;
	return per[x]=find(per[x]);
}
void join(int x,int y)
{
	int dx=find(x);
	int dy=find(y);
	if(dx!=dy)
	{
		per[dy]=dx; //如果根节点不同,并到一起注意dy的根节点为dx                            ;
		num[dx]+=num[dy];//就是以dx为根节点的树有多少节点 
	}
}
int main()
{
	int T,i,a,b;
	while(~scanf("%d",&T))
	{
		for(i=1;i<1000;i++)
		{
			per[i]=i;//把每个元素的根节点都为它本身 
			num[i]=1;//数组初始化为1 
		}
		for(i=0;i<T;i++)
		{
			scanf("%d %d",&a,&b);
			join(a,b);
		}
		int m=0;
		for(i=0;i<1000;i++)//sum[i]指的是以i为根节点时这棵树的节点 ,求出节点最大值 
			if(num[i]>m)
			m=num[i];	
		printf("%d\n",m);
	}
	return 0;
}

More is better

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


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.

这道题目的目的是想知道经过一系列的合并操作之后,查询在所有的子树中,秩的最大值是多少,简而言之,就是最大的那颗子树包含了多少个节点。

很显然,这个问题也能够同时使用两种优化策略,只不过因为要求最大秩的值,需要有一个变量来记录。那么在哪个地方来更新它是最好的呢?我们知道,在按秩进行合并的时候,需要比较两颗待合并子树的秩,因此可以顺带的将对秩的最大值的更新也放在这里进行,实现代码如下:

*我的思路大概是,先建立一个并查集数组,一个标记数组(主要为了防止超时),一个组员数量数组。首先先把并查集数组初始话为本身,并把组员数量初始化为1,之后就是按代码上理解下思路*/
#include<stdio.h>
int per[1000000];
int num[1000000];
int find(int x)
{
	if(per[x]==x)
	return x;
	return per[x]=find(per[x]);
}
void join(int x,int y)
{
	int dx=find(x);
	int dy=find(y);
	if(dx!=dy)
	{
		per[dy]=dx;
		num[dx]+=num[dy];
	}
}
int main()
{
	int n,i,a,b;
	while(~scanf("%d",&n))
	{
		if(n==0)
		{
		printf("1\n");//在讨论区看到的,不知道为什么? 
		continue;
		}
		for(i=1;i<=1000000;i++)
		{
			per[i]=i;
			num[i]=1;
		}
		int max=0;
		for(i=0;i<n;i++)
		{
			scanf("%d %d",&a,&b);//求得输入的数字最大是多少,因为爆过一次,所以加上这个  
			if(a>max)
			max=a;
			if(b>max)
			max=b;
			join(a,b);
		}
		int m=0;
		for(i=1;i<=max;i++)//直接从1求到max出即可,求出真正最大值  
		{
			if(num[i]>m)
			m=num[i];
		}
		printf("%d\n",m);
	}
	return 0;
}



你可能感兴趣的:(子树包含了多少个节点(并查集)——czy的工程VS hdoj1856 More is better)