并查集

本文介绍了一种使用并查集数据结构管理江湖门派的技术。通过将成员的直接上级设定为堂主,可以高效地进行门派合并,避免自相残杀,最终统计门派数量。
有情人终成兄妹

相信这样的狗血剧情韩剧里有很多。
在这里插入图片描述
这种情况往往只会出现在特别特别大的家庭里,而且家庭成员分布各地。但人一般都不会看族谱,所以在根本不知道对方是自己妹妹的情况下与之相爱。
在这里插入图片描述
将其变成
在这里插入图片描述
那我们马上就可以知道我们祖先是谁,碰到妹子可以直接问她祖先是谁就可以防止上面的尴尬了。
在这里插入图片描述

不好意思以上纯属本人玩笑。
好的正经点,古时江湖两人决斗后发现是同门人岂不是很尴尬,但是一级一级上去问又太麻烦了,假如每个成员的直接上级都变成堂主,在决斗之前先问问对方自己的堂主是谁,不就可以避免自相残杀让别的门派看笑话了吗?正好并查集可以实现每个人上一级直接就是堂主。

首先呢要实现每个成员的直接上级就是堂主,哪就先得知道堂主是谁(也就相当于一棵树的根);
接下来我用代码展示
1.找到堂主
2.将 从此成员一直到堂主 这条路径上每个成员的直接上级变成堂主

代码如下:

int find_boss(int boss)
{
// 此处为 1 号操作
    int dd = boss, t;
    while(root != member[boss])// member数组元素代表每个成员直接上级,例如member[i]代表i的直接上级
        boss = member[boss];// 当某个成员直接上级为自己时,说明他就是堂主!!!
// 此处为 2 号操作        
    while(dd != boss)// 此时 boss已经是真正的boss(堂主)了!!!
    {
        t = member[dd];
        member[dd] = boss;
        dd = t;
    }
    return boss;
}

但最开始是没有门派的,也可以说每个人就是一派;所以 member 数组初始化如下:

for(i = 1; i <= n; i++)
            member[i] = i;

1.假如后来堂主都想着合并帮派,每个门派都会安排人(人数不定)出去
2.遇到人就先问他属于哪个门派
3.假如不属于同一门派,则双方上报堂主
4.双方门派堂主通过决斗,赢家合并对方门派,成为新门派堂主
5.求最终门派数量

代码如下:

int person1, person2;
            scanf("%d%d",&person1,&person2);// 此为相遇的两人
            
            person1 = find_boss(person1);
            person2 = find_boss(person2);
            if(person1 != person2)// 堂主不为统一位,则堂主双方堂主决斗
                member[person1] = person2;// 我们这里固定赢家为 2 方
                // 因为最终都是变成一个门派

最终统计剩余门派
1.我们先要把每个江湖人物的堂主找出
2.再判断堂主是否为自己,一个堂主即为一个门派

代码如下:

int ans = 0for(i = 1; i <= n; i++)
            member[i] = find_boss(i);
            // 找出每个江湖人物的堂主
        for(i = 1; i <= n; i++)
            if(i==member[i]) ans++;

最终代码如下:

#include<stdio.h>
int member[10000100]={0};
int find_boss(int boss)
{
    int dd = boss, t;
    while(boss != member[boss])
        boss = friend[boss];
    while(dd != boss)
    {
        t = member[dd];
        member[dd] = boss;
        dd = t;
    }
    return boss;
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int i;
        for(i = 1; i <= n; i++)
            member[i] = i;
            
        while(m--)
        {
            int person1, person2;
            scanf("%d%d",&person1,&person2);
            
            person1 = find_boss(person1);
            person2 = find_boss(person2);
            if(person1 != person2)
                member[person1] = person2;
        }
        for(i = 1; i <= n; i++)
            member[i] = find_boss(i);
            
        for(i = 1; i <= n; i++)
            if(i==member[i])ans++;
            
        printf("%d\n",ans);
    }
    return 0;
}

谢谢!!!

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值