POJ 1703 ----Find them, Catch them // 种类并查集 同类型题目::POJ1182-----食物链

Find them, Catch them

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.




 

参考网址:::::https://blog.csdn.net/jaihk662/article/details/52013762  题解参考

参考网址:::https://blog.csdn.net/qq_33583069/article/details/51225372  注释参考

::::::https://blog.csdn.net/yinghui_yht/article/details/53363012 注释参考

参考网址:::https://blog.csdn.net/qq_18738333/article/details/48396497  代码参考


题意:某同一个城市有两个团伙,给出t代表有多少组数据,n代表人数,m代表关系的数目,如果输入的是A的话,就是让我们来判断这两个人是否属于同一个团伙,如果输入的是D 的话,旧表示这两个人是不同的团伙。

思路:用到算法是种类并查集,用fa数组来存放节点与根节点,用gang数组来存放关系。

用0代表与gang[i]是同一个同伙的,1代表i与gang[i]不是同一个同伙的

重点1:在find1()函数中,我们用到

    int temp=fa[t];
    fa[t]=find1(temp);
    gang[t]=(gang[t]+gang[temp])%2;

这一语句,其语义是,如果当前节点t与新节点或者新节点与旧节点的关系都是1或者0,那么当前节点t与新节点的关系就好判断了,要么是同伙,要么不是同伙。

重点2 :

void  union_set(int a,int b)
{
    int roota=find1(a);
    int rootb=find1(b);
    if(roota!=rootb)
    {
        fa[rootb]=roota;
        gang[rootb]=(gang[a]+1-gang[b])%2;
    }
}
用来查找a和b的祖先节点,如果其祖先节点不同的话,那么其关系就不确定,所以就要将两者的祖先链接起来,rootb的祖先节点是roota,再下面一条语句是用来判断a和b是什么样的关系
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
#define maxn 100100
int fa[maxn+1];
int gang[maxn+1];
int n,k;
void inist()
{
    for(int i=0;i<=n;i++)
    {
        fa[i]=i;
        gang[i]=0;
    }
}
int find1(int t)
{
    if(fa[t]==t)
        return fa[t];
    int temp=fa[t];
    fa[t]=find1(temp);
    gang[t]=(gang[t]+gang[temp])%2;
    return fa[t];
}
void  union_set(int a,int b)
{
    int roota=find1(a);
    int rootb=find1(b);
    if(roota!=rootb)
    {
        fa[rootb]=roota;
        gang[rootb]=(gang[a]+1-gang[b])%2;
    }
}
int solve(int a,int b)
{
    int roota=find1(a);
    int rootb=find1(b);
    if(roota!=rootb)
    {
        return 1;
    }
    else
    {
        if(gang[a]!=gang[b])
        {
            return 2;
        }
        else
        {
            return  3;
        }
    }
}
int main()
{
    int t;
    char op;
    int a,b;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        inist();
        for(int i=0;i<k;i++)
        {
             getchar();
             scanf("%c%d%d",&op,&a,&b);
            if(op=='D')
            {
                union_set(a,b);
            }
            else
            {
                int res=solve(a,b);
                if(res==1)
                {
                    printf("Not sure yet.\n");
                }else if(res==2)
                {
                    printf("In different gangs.\n");
                }else
                {
                    printf("In the same gang.\n");
                }
            }
        }
    }
}

对于确定a和b的关系数组的做法和find1()函数修改关系的做

法,不是很理解,目前还没有彻底掌握,很迷茫的感觉,可能有

许多错误的地方,欢迎大家评论,谢谢~~~

注:详细注释

#include<stdio.h>
#include<iostream>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
const int MAXN = 100100;
int fa[MAXN];
int gang[MAXN];
int n, k;

void init()
{
	for (int i = 0; i <= n; i++)
	{
		fa[i] = i;
		gang[i] = 0;//代表团伙关系,0代表i与gang[i]是同一个团伙的,1代表i与gang[i]不是同一个团伙的
	}
}

int find1(int t)
{
//在find中更新gang的关系,当前节点t的父亲的父亲是根节点,我们可以通过当前节点t和它付钱的关系
//来判断当前节点t与根节点(其父亲的父亲的)关系
	if (fa[t] == t)
		return fa[t];
	int temp = fa[t];
	fa[t] = find1(temp);//用来找祖先节点
	gang[t] = (gang[t] + gang[temp]) % 2;//代表当前节点t与其父亲节点temp的关系
//如果t与旧祖先的关系和旧祖先与新祖先的关系都为1或者0,那么t与新祖先的关系要么是同一个团伙,要么是不同的团伙。
	cout<<"gang["<<t<<"]= "<<gang[t]<<endl;
	return fa[t];
}

void union_set(int a, int b)
{
	int roota = find1(a);
	int rootb = find1(b);
	if (roota != rootb)//根不相同,关系还不确定
	{
		fa[rootb] = roota;//更新根节点b中的值,将根节点a与根节点b相连接
//其中roota是rootb的父亲
		gang[rootb] = (gang[a] + 1 - gang[b]) % 2;
//确认a和b的关系
		cout<<"gang["<<rootb<<"]= "<<gang[rootb]<<endl;
	}
}

int solve(int a, int b)
{
	int roota = find1(a);
	int rootb = find1(b);
	if (roota != rootb)
	{
		return 1;
	}
	else
	{
		if (gang[a] != gang[b])
			return 2;
		else
			return 3;
	}
}

int main()
{
	int casen;
	scanf("%d", &casen);
	while (casen--)
	{
		scanf("%d%d", &n, &k);
		init();
		char op;
		int a, b;
		for (int i = 0; i < k; i++)
		{
			cin >> op;
			scanf("%d%d", &a, &b);
			if (op == 'D')
			{
				union_set(a, b);
			}
			else
			{
				int ret = solve(a, b);
				if (ret == 1)
					printf("Not sure yet.\n");
				else if (ret == 2)
					printf("In different gangs.\n");
				else
					printf("In the same gang.\n");
			}
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值