poj Find them, Catch them(关系并查集)

21 篇文章 0 订阅
Find them, Catch them

Description

The police office in Tadu City decides to say ends to the chaos, as launch actions to root up the TWO gangs in the city, Gang Dragon and Gang Snake. However, the police first needs to identify which gang a criminal belongs to. The present question is, given two criminals; do they belong to a same clan? You must give your judgment based on incomplete information. (Since the gangsters are always acting secretly.) 

Assume N (N <= 10^5) criminals are currently in Tadu City, numbered from 1 to N. And of course, at least one of them belongs to Gang Dragon, and the same for Gang Snake. You will be given M (M <= 10^5) messages in sequence, which are in the following two kinds: 

1. D [a] [b] 
where [a] and [b] are the numbers of two criminals, and they belong to different gangs. 

2. A [a] [b] 
where [a] and [b] are the numbers of two criminals. This requires you to decide whether a and b belong to a same gang. 

Input

The first line of the input contains a single integer T (1 <= T <= 20), the number of test cases. Then T cases follow. Each test case begins with a line with two integers N and M, followed by M lines each containing one message as described above.

Output

For each message "A [a] [b]" in each case, your program should give the judgment based on the information got before. The answers might be one of "In the same gang.", "In different gangs." and "Not sure yet."

Sample Input

1
5 5
A 1 2
D 1 2
A 1 2
D 2 4
A 1 4

Sample Output

Not sure yet.
In different gangs.
In the same gang.
题目大意:
有两个不同的帮派,每个帮派至少有一个人。 判断两个人是否属于同一个帮派。
              有 T 组测试数据。
              给你 N 个人,编号从 1 到 N,操作 M 次。
              每次操作输入一个字符和两个数 x ,y 
              如果字符为 A 则判断 x 和 y 是否属于同一个帮派,并且输出结果。
              如果字符为 D 则明确告诉你 x 和 y 是属于不同帮派的。
思路:
通过祖先来进行分类,加一个rank[]数组,表示其与祖先是否为同一类,1表示为同一类,0表示为不同类。
ps:好吧,看题解看了好久好久才勉强明白,主要是判断是否为同一类有点难理解,所以对于rank[]值的改变应该多写例子多加思考才容易想明白。。
代码:
#include<stdio.h>
const int N=100000+10;
int pre[N],rank[N];//rank保存其与祖先的关系,1表示为同一类,0则为不同类
void init(int n)//初始化
{
    for(int i=1;i<=n;i++)
    {
        pre[i]=i;
        rank[i]=1;//自己与自己为同一类
    }
}
int Find(int x)
{
    if(x!=pre[x])
    {
        int t=pre[x];
        pre[x]=Find(pre[x]);
        rank[x]=(rank[x]+rank[t]+1)&1;//根据子节点与父亲节点的关系和父节点与爷爷节点的关系,推导子节点与爷爷节点的关系(爷爷节点指的就是其祖先)
//        if(rank[x]==rank[t])//如果与其祖先是同一类
//            rank[x]=1;//标记为1
//        else//否则
//            rank[x]=0;//标记为0
    }
    return pre[x];
}
void join(int x,int y)
{
    int fx=Find(x),fy=Find(y);
    if(fx!=fy)
    {
        pre[fx]=fy;
        rank[fx]=(rank[x]+rank[y])&1;//将两个人分到不同的帮派
//        if(rank[x]==rank[y])//如果两个人的rank相同,则将rank[fx]置为0,表示与父节点不属于同一类,则将x和y分为了不同类
//            rank[fx]=0;
//        else//否则,若有一个人与其父节点不同类
//            rank[fx]=1;//则将rank[fx]置为1,则将x和y分为了不同类
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        init(n);
        while(m--)
        {
            char s[10];
            int x,y;
            scanf("%s %d%d",s,&x,&y);
            if(s[0]=='D')
                join(x,y);
            else
            {
                int fx=Find(x),fy=Find(y);
                if(fx!=fy)//如果根节点不相同,则说明可能有多种情况
                    printf("Not sure yet.\n");
                else if((rank[x]+rank[y])&1)//根节点相同,判断是否为同一类
                    printf("In different gangs.\n");
                else
                    printf("In the same gang.\n");
            }
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值