题面:
Problem E: 变形金刚
Description
有一天Stubird买了一台变形金刚,店员说,这台变形金刚和其他那种骗小孩子的不一样 他真的能变形。 这台变形金刚有n个部件,他们能互相连接,组成机器人,当然,也可以变形。 但是有一天,The tesseract 的能量突然消失了,部件散落一地,当然有些部件还连接着。 现在你只有把部件全部连接起来,他就能变回原样,例如,有4个部件,1,2是连接的,3,4也是连接着的 ,你只需要把1和3连接起来(1,4或者2,3或者2,4)他就能变回原样啦。 他现在问你最少需要多少次连接才能把它变回原样?
Input
第一行一个T,表示有T个测试样例 接下来一个n和m(n<=10^5,0<=m<=10^5),n表示部件个数,m表示有多少个部件还连接着 下面m行,每行u,v表示部件u,v是连接着的。(1<=u,v<=n)
Output
求最小的连接次数
Sample Input
21 05 21 23 4
Sample Output
02
好久没写并查集,还错了两次
贴代码啦:
#include <iostream>
#include <cstdio>
using namespace std;
#define maxn 100005
struct node
{
int parent;
int rank;
}elem[maxn];
int n,m,t;
void Init()//初始化
{
for(int i=1;i<=n;i++)//注意下标
{
elem[i].parent=i;
elem[i].rank=1;
}
}
int Find(int x)//寻找根节点
{
int root,tmp;
tmp=x;
while(x!=elem[x].parent)
{
x=elem[x].parent;
}
root=x;
x=tmp;
while(x!=elem[x].parent)
{
tmp=elem[x].parent;
elem[x].parent=root;
x=tmp;
}
return root;
}
void Union(int a,int b)//合并
{
int x,y;
x=Find(a);
y=Find(b);
if(elem[x].rank>=elem[y].rank)
{
elem[y].parent=elem[x].parent;
elem[x].rank+=elem[y].rank;
}
else
{
elem[x].parent=elem[y].parent;
elem[y].rank+=elem[x].rank;
}
}
int main()
{
int x,y,a,b,cnt;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
Init();
for(int i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
a=Find(x);
b=Find(y);
if(a!=b)
Union(x,y);
}
cnt=0;
for(int i=1;i<=n;i++)
{
if(elem[i].parent==i)//判断几个集合
cnt++;
}
printf("%d\n",cnt-1);
}
return 0;
}