链接: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; }