并查集
让我们先来了解一下什么是并查集 假设现在有10个人 给你一些信息判断他们有多少个班
1和2是一个班
3和4是一个班
5和2是一个班
4和6是一个班
2和6是一个班
8和7是一个班
9和7是一个班
1和6是一个班
2和4是一个班
解决这个问题 先假设他们都不在一个班 每个人都有独立的班级 然后利用条件进行合并 最终可以得到 5 2 1 3 4 6是一个班级的
7 8 9是一个班级的 10是一个班级的
那具体应该怎样去实现呢 去找每个人的BOSS 然后让这个BOSS归顺另一个BOSS 我们假设右边的BOSS都归顺于左边的BOSS
我们用一个数组f来储存开始的状态 即每个人都有自己独立的班级 换句话说就是每个人都是自己的BOSS 此时f[i]=i
我们知道1和2是同一班级的之后 让2去归顺于1 即f[2]=1 这时2和1都是同一个班级1的了
接下来是3和4 他们的boss也都是自己 同上得f[4]=3
5和2 2的boss是1 5的boss是5 这时就为f[1]=5
4和6 4的boss是3 6的boss是他自己 这时 f[6]=3
同上进行修改 在修改的过程中还有一个小技巧让找boss的时间减少 就是在找boss的过程中把中间的学生值都修改为boss 这样会加快找boss的速度 具体解释让我们来看代码
# include <iostream>
# include <cstdio>
using namespace std;
int f[1100]={0},n,m,k,sum=0;
void init()//让每个人都是自己的boss 都有自己独立的班级
{
int i;
for(i=1;i<=n;i++)
f[i]=i;
return ;
}
int getboss(int v)//这里就是找这个人的boss 利用递归一直到找到boss为止
{
if(f[v]==v)//如果这个人的班级就是自己的班级 那么他就是boss 因为他并没有归顺于别人
return v;
else
{
f[v]=getboss(f[v]);//这里就是在路径中进行压缩 在找boss的过程中把路径中的人的值都改为找到的boss的编号
//这样可以加快找boss的速度
return f[v];
}
}
void merge(int v,int u)//对找到的boss进行归顺合并
{
int t1,t2;
t1=getboss(v);
t2=getboss(u);//分别找到左右的boss
if(t1!=t2)//判断两个boss是不是一个
{
//如果不是一个 那就让右边归顺于左边
f[t2]=t1;
}
return ;
}
int main()
{
int i,x,y;
scanf("%d%d",&n,&m);
init();//进行初始化
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
merge(x,y);
}
for(i=1;i<=n;i++)
{
if(f[i]==i)//这个人没有归顺于任何人 则这就是一个班级
sum++;
}
printf("%d\n",sum);
return 0;
}
/*
10 9
1 2
3 4
5 2
4 6
2 6
8 7
9 7
1 6
2 4
3
*/