普通并查集之宗教问题(题目)

题目:宗教问题
第一行输入n(人数),m(关系数)
接着换行输入m个关系
换行输入询问次数q
换行输入询问每组询问对应一组输出:如果是则输出YES,否或不一定都输出NO


例:
5 35个人,3个关系
1 2     1说他在自己的教堂里看到过2
2 3     2说他在自己的教堂里看到过3
4 5     4说他在自己的教堂里看到过5
2       2组询问次数
1 3     问:13是同一个教堂吗?             输出YES
1 5     问:15是同一个教堂吗?             输出NO





#include<stdio.h>
int tree[1000];                  //注意这个数组要建到外面

int find(int x)
{
    return tree[x]==x?x:find(tree[x]);   //找根(用递归找)
}

void uset(int a, int b)
{
    a=find(a);   //先找到a,b的根
    b=find(b);
    if(a==b)         //现在a,b是自己的根,tree[a],tree[b]里的是a,b//a,b 是同一个集合 ,(属于同一个根)
        return ;
    tree[b]=a;         //将b和a连起来(将b的根和a的根连起来)
}

 int main()
 {
    int n,i,m,a,b;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
        tree[i]=i;          //初始化 先都自己成为一个单独根
    for(i=0;i<m;i++)
    {
        scanf("%d%d",&a,&b);
        uset(a,b);           //将他们的根连起来
    }
    scanf("%d",&n);            //询问次数
    for(i=0;i<n;i++)
    {
        scanf("%d%d",&a,&b);    //a和b是同一个根吗?
        if(find(a)==find(b))     //找a和b的根
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
 }
压缩路径:查找过的节点都直接连到根上,降低树的高度,所以递归查找时深度遍历的
层数降低了,所以越用越快

#include<stdio.h>
int tree[1000];

int find(int x)
{                        //压缩路径在这里
    return tree[x]<0?x:(tree[x]=find(tree[x]));//查找过的节点连到根,越用越快
}

void uset(int a, int b)
{
    if((a=find(a))==(b=find(b)))         //如果a,b是同一个集合 ,同一个根
        return ;
    if(tree[a]<tree[b])       //越小高度越高
        tree[b]=a;
    else if(tree[a]>tree[b])
        tree[a]=b;
    else
    {
        tree[a]=b;     //这里,谁是谁根都行
        tree[b]--;     //合并后,b的高度增加1,因为根的高度是负数,所以减1
    }
}

 int main()
 {
    int n,i,m,a,b;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)    //-1 意思是根,高度为1,小于0才为根
        tree[i]=-1;      // 都初始化为-1(根)
    for(i=0;i<m;i++)
    {
        scanf("%d%d",&a,&b);
        uset(a,b);           //将他们的根连起来
    }
    scanf("%d",&n);            //询问次数
    for(i=0;i<n;i++)
    {
        scanf("%d%d",&a,&b);    //a 和 b 是同一个宗教吗?
        if(find(a)==find(b))     //找a和b的根
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值