并查集入门

前几天学长跟我们讲了并查集的原理和方法,我又看了一些博客,做了几道模板题,感觉还不错,来简单介绍一下并查集的一些东西

并查集,顾名思义就是合并、查找的一系列操作。

当今社会人脉极为重要,我们出门在外很多时候靠的就是朋友互帮互助,当你和一个不认识的人发生了矛盾,因为考虑到经济原因不知道要不要动手的时候,你们突然发现有一个共同的朋友B,朋友的朋友就是朋友,之后化干戈为玉帛。当然,由于朋友太多,有时候你和你的对手没有办法一个一个的确定有没有共同的朋友,这时候就需要确定一个声望高权利大的人作为自己的牌面,你说可是跟A市长混的,你算老几?对方一听,我也跟A市长混,哈哈,误会误会,之后两人手牵手去喝酒。但让如果对面说S市长是谁?不认识,我只认识B市长。那就不用考虑那么多了,骂他就完事了,毕竟谁先动手谁完蛋。

以上只是简单介绍了“查找”,那么如何合并呢?

你在路上和一个人发生了矛盾,你只认A市长,但是对面是P省长的人,这时你的老大A市长感觉和省长发生矛盾很不划算,想法设法邀请到家里吃顿便饭,因为省长的职位更大,所以市长以后跟P省长混,之前市长手下的所有人都算是跟P省长混,那么你的老大自然也变成了P省长,以后出门只需要说我跟P省长混!

下面来看一下代码

int find(int x)
{
    int r = x;
    while(pre[r]!=r)
    {
        r = pre[r];	//直到找到老大为止,重所周知,老大只跟自己混
    }
    //路径压缩
    int a,b,c;
    a = x;
    while(a!=r)
    {
        b = pre[a];
        pre[a] = r;
        a = r;
    }  
    return r;
}

关于路径压缩
还看我们上面的例子,如果A市长偷偷摸摸地跟了P省长,没有声张,当以后A市长的人和别人发生了矛盾,每次都会找到A,因为他们还以为他们的老大是A,A去和对面的人说我老大是P省长,表示他们都是P的人,每次如此,A市长也不耐烦了,跟下面的人公开了,说以后你们的老大是P省长,出去混,不要再提我了!直接提P老大的名字就好了!
在这里插入图片描述

int join(int x, int y)
{
    int a =find(x);
    int b= find(y);
    if(a!=b)
    {
    
//这里可以加个判断条件,可以是谁的值大谁当老大或者是其他条件
        pre[a] = pre[b];
    }
}

这里可以看一下HDU的一道题 HDU畅通工程

AC代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
using namespace std;
int pre[1010];
int find(int x)
{
    int r = x;
    while(pre[r]!=r)
    {
        r = pre[r];
    }
    //路径压缩
    int a,b,c;
    a = x;
    while(a!=r)
    {
        b = pre[a];
        pre[a] = r;
        a = r;
    }  
    return r;
}
int join(int x, int y)
{
    int a =find(x);
    int b= find(y);
    if(a!=b)
    {
        pre[a] = pre[b];
    }
}
int main()
{
    int m,n;
    int a,b;
    int s[10000];
    while(cin>>n>>m)
    {
        int sum = 0;
        memset(s,0,sizeof(s));
        for(int i=1;i<=n;i++)
            pre[i] = i;

        while(m--)
        {
            cin >>a>>b;
            join(a,b);
        }
        for(int i=1;i<=n;i++)
        {
            s[find(i)]=1;
        }
        for(int i=0;i<=n;i++)
            sum+=s[i];
        cout<<sum-1<<endl;
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值