2014年第四届“华为杯”南邮程序设计竞赛,选拔赛第二题 亲友团问题

链接:http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1798

题目B:亲友团问题

时间限制(普通/Java):6000MS/18000MS          运行内存限制:65536KByte

问题描述

在2014“华为杯”南邮大学生团体歌唱大赛每一个轮比赛现场,众多亲友团是一道亮丽的风景,他(她)们或来助威、或来观摩、或来刺探对手情报,不同亲友团之间偶尔还起冲突。为避免安全问题,主办方在赛场会划分许多独立区域,每一个区域安置一个亲友团,现在请你根据主办方提供的比赛现场信息,预测至多需要划分出多少个独立区域。

我们将主办方提供的比赛现场信息进行简化,1开始按顺序给进入比赛现场的每位亲友分配一个编号,依次为12...KK亲友总数,为保护隐私,主办方只能告诉你M组两个不同亲友属于同一亲友团信息,这些信息有可能重复。

问题输入

输入包括多个测试用例,首先给出测试用例数N,接着给出N个测试用例,1≤N≤100。

每一个测试用例包括M+1行,首先给出两个整数K和M;再依次给出M行,每行给出两个不同正整数i和j,表示两个不同亲友i和j属于同一亲友团,i≠j,1≤i≤K,1≤j≤K,,1≤K≤10000,1≤M≤10000。

问题输出

输出包括多行,对于每个测试用例,输出一行,给出至多需要划分出的独立区域数量。

样例输入

2

3 1

1 2

3 2

1 2

2 3

样例输出

2

1

提示

本题纯属虚构,题目中输入数据和输出数据在一行中均以空格分隔,赛后酌情进行重新测试。


主要利用并查集解决问题代码如下

#include<cstdio>
int par[10000],rank[10000];
void init(int n)
{
	for(int i=0;i<n;i++)
	{
		par[i]=i;
		rank[i]=0;
	}
}
//查询树的根
int find(int x)
{
	if(par[x]==x)
		return x;
	else
	{
	return par[x]=find(par[x]);
	}
}
//合并x和y所属集合
void unite(int x,int y)
{

	x=find(x);
	y=find(y);
	if(x==y) return;

	if(rank[x]<rank[y])
	{
	par[x]=y;
	}
	else
	{
	par[y]=x;
	if(rank[x]==rank[y])
		rank[x]++;
	}

}
int main(void)
{
	int t,i,k,m,ans;
	int a[10000],b[10000];
	scanf("%d",&t);
	while(t--)
	{
		ans=0;
		scanf("%d%d",&k,&m);
		init(k);
		for(i=0;i<m;i++)
		{
			scanf("%d%d",&a[i],&b[i]);
			unite(a[i]-1,b[i]-1);
		}
		for(i=0;i<k;i++)
			if(i==par[i])
				ans++;
		printf("%d\n",ans);
	}
	return 0;
}


你可能感兴趣的:(C++,设计,华为)