链接:http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1798
题目B:亲友团问题
时间限制(普通/Java):6000MS/18000MS 运行内存限制:65536KByte
问题描述
在2014“华为杯”南邮大学生团体歌唱大赛每一个轮比赛现场,众多亲友团是一道亮丽的风景,他(她)们或来助威、或来观摩、或来刺探对手情报,不同亲友团之间偶尔还起冲突。为避免安全问题,主办方在赛场会划分许多独立区域,每一个区域安置一个亲友团,现在请你根据主办方提供的比赛现场信息,预测至多需要划分出多少个独立区域。
我们将主办方提供的比赛现场信息进行简化,从1开始按顺序给进入比赛现场的每位亲友分配一个编号,依次为1、2、...、K,K为亲友总数,为保护隐私,主办方只能告诉你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;
}