擒贼先擒王(并查集)
题目描述:
快过年了,犯罪团伙也开始为了年终奖而奋斗,最近小明所在社区发生许多抢劫事件,由于强盗人数过于庞大,作案频繁,警方想查清楚到底有几个犯罪团伙实在是不容易了,警察叔叔还是搜索到了一些线索想让你分析有多少团伙。
输入描述:
第一行输入两个数n,m分别为有n个强盗,强盗之间的关系有m条。接下来的m行每行输入两个数x,y表示是一伙。
输出描述:
输出一共有几个团伙
输入样例:
11 10
1 2
3 4
5 2
4 6
2 6
7 11
8 7
9 7
9 11
1 6
输出样例:
3
思路:
首先每个编号为数组下标的贼的boss都是本身,然后对输入的两个有关系的贼,用递归函数把他们的boss找出来,让一个boss归顺另一个boss,这样连他们的手下都归顺了,最后遍历数组,如果贼的boss为其本身,即f[i]==i,则为一个团伙,只要找出团伙的boss就知道有几个团伙了。
代码:
#include<stdio.h>
int f[1100]; //用于存放每个编号为数组下标的贼的boss
int n,m;
void init()
{ //初始化,每个贼的boss都为自己
for(int i=1;i<=n;i++)
f[i]=i;
return ;
}
int find(int v)
{ //寻找贼的boss
if(f[v]==v)
return v;
else
{ //下面这一步为路径压缩,不然会形成一个长链,不方便找boss,运行会超时
f[v]=find(f[v]); //将每个贼的boss直接等于团伙头目,而不是一层一层的寻找boss
return f[v];
}
}
void merge(int v,int u)
{
int t1,t2;
t1=find(v); //寻找两个贼的boss
t2=find(u);
if(t1!=t2)
{ //如果两个贼的boss不相等
f[t2]=t1; //将一个贼的boss归顺另一个贼的boss,其整个团队都归顺。
}
return ;
}
int main()
{
int x,y,sum=0;
scanf("%d %d",&n,&m);
init(); //初始化
for(int i=1;i<=m;i++)
{ //输入贼之间的关系
scanf("%d %d",&x,&y);
merge(x,y); //并查集
}
for(int i=1;i<=n;i++)
if(f[i]==i) //如果贼的boss为自己,则是整个团伙的头,就算一个团伙
sum++;
printf("%d",sum);
return 0;
}