【并查集】并查集详解（转）

7 篇文章 0 订阅

4 2 1 3 4 3

int pre[1000 ];

int find(int x)                                                                                                         //查找根节点

int r=x;

while ( pre[r ] != r )                                                                                              //返回根节点 r

r=pre[r ];

int i=x , j ;

while( i != r )                                                                                                        //路径压缩

{

j = pre[ i ]; // 在改变上级之前用临时变量  j 记录下他的值

pre[ i ]= r ; //把上级改为根节点

i=j;

}

return r ;

}

void join(int x,int y)                                                                                                    //判断x y是否连通，

//如果已经连通，就不用管了 //如果不连通，就把它们所在的连通分支合并起,

{

int fx=find(x),fy=find(y);

if(fx!=fy)

pre[fx ]=fy;

}

http://i3.6.cn/cvbnm/6f/ec/f4/1e9cfcd3def64d26ed1a49d72c1f6db9.jpg

int find(int x)                                                                  //查找我（x）的掌门

{

int r=x;                                                                       //委托 r 去找掌门

while (pre[r ]!=r)                                                        //如果r的上级不是r自己（也就是说找到的大侠他不是掌门 = =）

r=pre[r ] ;                                                                   // r 就接着找他的上级，直到找到掌门为止。

return  r ;                                                                   //掌门驾到~~~

}

void join(int x,int y)                                                                   //我想让虚竹和周芷若做朋友

{

int fx=find(x),fy=find(y);                                                       //虚竹的老大是玄慈，芷若MM的老大是灭绝

if(fx!=fy)                                                                               //玄慈和灭绝显然不是同一个人

pre[fx ]=fy;                                                                           //方丈只好委委屈屈地当了师太的手下啦

}

#include int pre[1000 ];
int find(int x)
{
int r=x;
while (pre[r ]!=r)
r=pre[r ];
int i=x; int j;
while(i!=r)
{
j=pre[i ];
pre[i ]=r;
i=j;
}
return r;
}
int main()
{
int n,m,p1,p2,i,total,f1,f2;
while(scanf("%d",&n) && n)         //读入n，如果n为0，结束
{                                                    //刚开始的时候，有n个城镇，一条路都没有 //那么要修n-1条路才能把它们连起来
total=n-1;
//每个点互相独立，自成一个集合，从1编号到n //所以每个点的上级都是自己
for(i=1;i<=n;i++) { pre[i ]=i; }                //共有m条路
scanf("%d",&m); while(m--)
{ //下面这段代码，其实就是join函数，只是稍作改动以适应题目要求
//每读入一条路，看它的端点p1，p2是否已经在一个连通分支里了
scanf("%d %d",&p1,&p2);
f1=find(p1);
f2=find(p2);
//如果是不连通的，那么把这两个分支连起来
//分支的总数就减少了1，还需建的路也就减了1
if(f1!=f2)
{
pre[f2 ]=f1;
total--;
}
//如果两点已经连通了，那么这条路只是在图上增加了一个环 //对连通性没有任何影响，无视掉
}
//最后输出还要修的路条数
printf("%d\n",total);
}
return 0;
}

• 0
点赞
• 1
收藏
觉得还不错? 一键收藏
• 0
评论
06-22 9867
07-03 1万+
10-03 754
09-28 139
08-01
11-07
12-26
08-25 234
04-28 1万+

“相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、付费专栏及课程。