亲属关系--并查集训练T1(并查集之老大合并问题)

5265: 亲属关系--并查集训练T1

时间限制: 1 Sec
内存限制: 128 MB
提交: 30
解决: 18

题目描述

T1.亲属关系(relation.pas)

【问题描述】

若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。

规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。

【输入格式】

第一行:三个整数n,m,p,(n<=5000,m<=5000,p<=5000),分别表示有n个人,m个亲戚关系,询问p对亲戚关系。

以下m行:每行两个数Mi,Mj,1<=Mi,Mj<=N,表示Ai和Bi具有亲戚关系。

接下来p行:每行两个数Pi,Pj,询问Pi和Pj是否具有亲戚关系。

【输出格式】

P行,每行一个’Yes’或’No’。表示第i个询问的答案为“具有”或“不具有”亲戚关系。

【输入样例】

6 5 3

1 2

1 5

3 4

5 2

1 3

1 4

2 3

5 6

【输出样例】

Yes

Yes

No

输入

输出

样例输入

样例输出

提示

来源

典型的并查集之老大合并问题!就像并查集详解里面讲的那样!

那里面说如果A的老大跟B的老大不是一个老大,又不想让他们打

架怎么办?可以让A的老大叫B的老大为老大啊!是不是?这个题

目就是这个意思,但是问题来了,用上面我写的那样数组存老大

可以实现吗?我感觉可以,但是事实没有成功!

我先发一份AC的代码!
#include<stdio.h>
#include<string.h>
int a[5010];
int Find(int x)
{
    int r=x,f,j;
    while(a[r]!=r)
    {
        r=a[r];
    }
    f=x;
    while(a[f]!=r)
    {
        j=a[f];
        a[f]=r;
        f=j;
    }
    return r;//这个找到老大之后,将这个数的小兵子的老大全部都存为现在的这个老大也就是路径压缩问题!
}
void mix(int x,int y)
{
    int f1,f2;
    f1=Find(x);f2=Find(y);
    if(f1!=f2)
    {
        a[f1]=f2;
    }
}//如果他们的老大不一样那么第一个的老大的老大就是第二个的老大
int main()
{
    int m,p,i,j,c,d,n;
    while(scanf("%d%d%d",&n,&m,&p)!=EOF)
    {
        memset(a,0,sizeof(a));
        for(i=1;i<=n;i++)
        {
            a[i]=i;
        }
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&c,&d);
            mix(c,d);
        }
        for(j=0;j<p;j++)
        {
            scanf("%d%d",&c,&d);
            if(Find(c)==Find(d))
            {
                printf("Yes\n");
            }
            else
            {
                printf("No\n");
            }
        }
    }
}
这个之所以AC是因为我
让这些小兵子去找他们自己的老大,看他们的老大是否一样去了

一开始我写的是用数组存他们各自的老大!

#include<stdio.h>
#include<string.h>
int a[5010];
int Find(int x)
{
    int r=x;
    while(a[r]!=r)
    {
        r=a[r];
    }
    return r;
}
void mix(int x,int y)
{
    int f1,f2;
    f1=Find(x);f2=Find(y);
    if(f1!=f2)
    {
        a[f1]=f2;//把B的老大当成A的老大的老大
    }
}
int main()
{
    int n,m,p,i,j,c,d;
    while(scanf("%d%d%d",&n,&m,&p)!=EOF)
    {
        memset(a,0,sizeof(a));
        for(i=1;i<=n;i++)
        {
            a[i]=i;
        }
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&c,&d);
            mix(c,d);
        }
        for(i=1;i<=n;i++)
        {
            printf("%d ",a[i]);
        }
        for(j=0;j<p;j++)
        {
            scanf("%d%d",&c,&d);
            if(a[c]==a[d])
            {
                printf("Yes\n");
            }
            else
            {
                printf("No\n");
            }
        }
    }
}

毋庸置疑,上面那个程序肯定是错误的!因为只有

把B的老大当成A的老大的老大,是的A的老大的老大知道他的老大是B的老大,但

是A以及A的小兵子知道他们的老大是B的老大吗?答案肯定是否定的!所以我们需

要一个函数Find1(int x,int y,int n)这个函数的功能是当A的老大的老大认B的

老大为老大时,A以及A的小兵子也要知道他们的老大是B的老大!上面这个程序的

运行<span style="font-family: Arial, Helvetica, sans-serif;">结果为</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><img src="https://img-blog.csdn.net/20150401212710199?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmFpZHVfMjM5NTU4NzU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">看到了吧,1只知道他的老大是2,二只知道他的老大是5,但是他</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">们不知道5的老大已经是4了?额?我们的老大什么时候认老大了</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">?妈的这让我们可怎么活啊?好吧,我也要认老大的老大为老大</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">去</span>
<span style="font-family: Arial, Helvetica, sans-serif;">下面有发一个AC代码啦!(小兵子认老大)</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;"></span><pre name="code" class="cpp">#include<stdio.h>
#include<string.h>
int a[5010],n;
int Find(int x)
{
    int r=x;
    while(a[r]!=r)
    {
        r=a[r];
    }
    return r;
    int i=x,j;
    while(a[i]!=r)
    {
        j=a[i];
        a[i]=r;
        i=j;
    }
}
int Find1(int x,int y,int n)
{
    int i,j,f;
    for(i=1;i<=n;i++)
    {
        if(a[i]==x)
        {
            f=i;
            while(a[f]!=y)
            {
                j=a[f];
                a[f]=y;
                f=j;
            }
        }
    }
}
void mix(int x,int y)
{
    int f1,f2;
    f1=Find(x);f2=Find(y);
    if(f1!=f2)
    {
        a[f1]=f2;
        Find1(f1,f2,n);
    }
}
int main()
{
    int m,p,i,j,c,d;
    while(scanf("%d%d%d",&n,&m,&p)!=EOF)
    {
        memset(a,0,sizeof(a));
        for(i=1;i<=n;i++)
        {
            a[i]=i;
        }
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&c,&d);
            mix(c,d);
        }
        /*for(i=1;i<=n;i++)
        {
            printf("%d ",a[i]);
        }*/
        for(j=0;j<p;j++)
        {
            scanf("%d%d",&c,&d);
            if(a[c]==a[d])
            {
                printf("Yes\n");
            }
            else
            {
                printf("No\n");
            }
        }
    }
}

毋庸置疑这个耗时又耗力!
 
 
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">看图便知!</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;"><img src="https://img-blog.csdn.net/20150401213913965?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmFpZHVfMjM5NTU4NzU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">所以还是在判断的时候让他们顺藤摸瓜,挨着找老大,最终找到</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">大老大吧!并查集真好玩!</span>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值