并查集—入门

所谓并查集,就是把一些有关的东西合并起来,方便查找。它的作用是快速判断两个数是否同一集合,与快速将两个集合并成一个集合求出一些节点之间的关系


并查集的主要操作有下面三种:

1、初始化:把每个点所在集合初始化为其自身;

2、查找:查找元素所在的集合,即根节点;

3、合并:将两个元素所在的集合合并为一个集合。


在并查集中,每个节点记录着它的父亲(或者是它的老祖宗),这样就可以方便的找到它这个集合的领头人。集合的领头人有一个特点,它的父亲是它自己,因为是它创造了它。如果某个特别的时刻,它发现它居然还有兄弟,它会认比较年长的作它的父亲,它的孩子们就认年长的兄弟作它们的老祖宗。这样这个家族日益庞大,它们有一个共同特点,有一个相同的老祖宗。(并查集原理)


为了让我能最快的找到我的老祖宗,我向父亲询问我的祖籍,直接把我的祖宗当作父亲记住。以后如果有孩子问我,谁是它的祖宗?我就把我的父亲告诉它,减少了访问真父亲的过程。据此原理,在把x加入y集合的时候,只要让x认y作父亲就可以了,上层变了,下层在搜索时,自然也会记住y。(路径压缩)


例题:(来源:caioj 1092)

n个人,m条关系(x,y),表示x和y是同一家族的。求最多可能有多少个家族。 


模版代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
 
int fa[100010];
 
int find_fa(int x)
{
    if(fa[x]!=x) return fa[x]=find_fa(fa[x]);//如果我不是家族的创造者 
    return x;
}
 
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) fa[i]=i;//初始化:每个人都是自己集合的标志 
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        int fx=find_fa(x),fy=find_fa(y);//查找老祖宗
        if(fx!=fy)
        {
            if(fx<fy) fa[fy]=fx;//合并集合:我的父亲认你当父亲当父亲,那我的爷爷就是你的父亲(我们是一个家族的) 
            else fa[fx]=fy;
            //只管更新父亲的关系就好了,孩子们找祖宗时,自然会向父亲询问最新情况 
        }
    }
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        if(find_fa(i)==i) cnt++;//每有一个创造者,就多了一个家族 
        //为什么不能改成 if(fa[i]==i) cnt++; ? (看回28行)因为fa中记录的不一定是最新的情况,必须先获得最新信息后再作判断 
    }
    printf("%d",cnt);
    return 0;
}



推荐:《并查集—应用》http://blog.csdn.net/a_bright_ch/article/details/77162197

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值