并查集

int pre[N]; //代表x的上级 
int zxy(int x) //x要去找他的老大,看看他和另y是不是同一个帮派 
{
    int r = x; //让r去找x的上级 
    while (pre[r] != r) //如果他的上级不是他自己 
    r = pre[r]; //就令r的上级去找他的上级,以此类推
    
    int i = x, j;
    while (i != r) //如果r的上级不是老大 
    {
        j = pre[i]; //这时来了个j说:我来帮r的上级来管理下属,r的上级你去找你的上级吧 
        pre[i] = r; //但是r却说:j大哥,不用你在这帮忙,
                    //我跟我的上级(pre[r])说了,他先让我暂时帮他管理一下,就不用麻烦您了。 
                    //这里就相当于r直接升了一个等级,占了他上级(pre[r])的位置。
                    //以此类推,就相当于r直接去找老大了(仔细想想对不对?)。 
        i = j; //j这时说:不过你的下属没人管了啊,我去帮你管管吧,你就去找老大吧。 
    } 
    return r; //老大现身(登登登----登---------) 
} 

int zhoier(int x , int y) //让x和y成为一个帮派的 
{
    int fx = zxy(x) , fy = zxy(y); //x和y通过zxy这个强大的天神终于找到了他们的老大
    if(fx != fy) //如果x和y的老大不是一个人 
        pre[fx] = fy;  //因为x的老大比较淡泊名利,所以就让y的老大当帮主,所以x的老大的上级就成了y的老大
                       //帮派合并完成!!! 
} 

并查集就是用来解决合并集合的,只要能灵活运用以上两种操作,那么对于并查集的基本几个问题就可以得出解了。

下面给一道例题:hdu-1232

并查集的思想在这道题中是十分明显的,对于每一条道路所连接的两个城市,每组两个城市各进行子集判断,只要稍微改一下zhoier函数就行,也是一道比较水的并查集的题:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm> 
int pre[1000];
int find(int x)
{
    return x == pre[x] ? x : x=find(pre[x]); 
} 
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--) { //下面这段代码,其实就是zhoier函数,只是稍作改动以适应题目要求 //每读入一条路,看它的端点p1,p2是否已经在一个连通分支里了 scanf("%d %d",&p1,&p2); f1=find(p1); f2=find(p2); //如果是不连通的,那么把这两个分支连起来 //分支的总数就减少了1,还需建的路也就减了1 if(f1!=f2) { pre[f2]=f1; total--; } //如果两点已经连通了,那么这条路只是在图上增加了一个环

      //对连通性没有任何影响,无视掉 }       //最后输出还要修的路条数 printf("%d ",total); } return 0; }
原文地址:https://www.cnblogs.com/Zhoier-Zxy/p/8433130.html