POJ1703【Find them, Catch them】(并查集模板题)

题目地址:POJ1703【Find them, Catch them】

题目描述:
Tadu市的警察局决定结束混乱,因此要采取行动,根除城市中的两大帮派:龙帮和蛇帮。然而,警方首先需要确定某个罪犯是属于哪个帮派。目前的问题是,给出两个罪犯,他们是属于同一个帮派吗?您要基于不完全的信息给出您的判断,因为歹徒总是在暗中行事。假设在Tadu市现在有N(N≤105)个罪犯,编号从1到N。当然,至少有一个罪犯属于龙帮,也至少有一个罪犯属于蛇帮。给出M(M≤105)条消息组成的序列,消息有下列两种形式:

  1. D [a] [b]
    其中[a]和[b]是两个犯罪分子的编号,他们属于不同的帮派;
  2. A [a] [b]
    其中[a]和[b]是两个犯罪分子的编号,您要确定a和b是否属于同一帮派。

输入描述:
输入的第一行给出给出一个整数T(1≤T≤20),表示测试用例的个数。后面跟着T个测试用例,每个测试用例的第一行给出两个整数N和M,后面的M行每行给出一条如上面所描述的消息。

输出描述:
对于在测试用例中的每条“A [a] [b]”消息,您的程序要基于此前给出的信息做出判断。回答是如下之一 “In the same gang.”,“In different gangs.”或“Not sure yet.”。

输入样例:

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

输出样例:

Not sure yet.
In different gangs.
In the same gang.

思路:
龙帮和蛇帮的罪犯各组成一个集合,设set[d]为罪犯d所属集合的代表元,set[d+n]为另一集合的代表元,1≤d≤n。函数set_find(i)查找罪犯i所属并查集的代表元,同时进行路径压缩,1≤i≤2n。
初始时set[d]=-1,即每个罪犯自成一个帮派。按照如下方法处理每条消息s:
确定a和b是否属于同一帮派(s[0]==‘A’)

  • 如果a和b不属同一帮派(set_find(a)!=set_find(b)),且a所属的帮派与b的另一帮派也不相同(set_find(a)!=set_find(b+n)),则不能确定a和b是否属于同一帮派;
  • 否则,如果罪犯a所属集合的代表元与罪犯b所属集合的代表元相同(set_find(a)=set_find(b)),则确定a和b同属一个帮派;
  • 否则,可以确定a和b属于不同的帮派。

题记:
find_set函数中返回的是set[p] = find_set(set[p]),而不是find_set(set[p])

参考链接:并查集讲解

代码:

#include<cstdio> 
#include<cstring>
const int maxn = 1e5+5;
int set[maxn + maxn];
int find_set(int p)// 查找p所在集合的代表元,用路径压缩优化
{
	if(set[p] < 0) return p;
	return set[p] = find_set(set[p]);
}
void join_set(int p,int q)// 将p所在的集合并入q所在的集合
{
	p = find_set(p);
	q = find_set(q);
	if(p != q)
	set[p] = q;
} 
int main()
{
	int t;
	char str[5]; 
	scanf("%d",&t);
	while(t--)
	{
		int n,m,a,b;
		memset(set,-1,sizeof(set));
		scanf("%d %d",&n,&m);
		while(m--)
		{
			scanf("%s%d%d",str,&a,&b);
			if(str[0] == 'A')
			{
				if(find_set(a) != find_set(b))//如果a 不属于 b 组织 
					if(find_set(a) != find_set(b+n))//如果a 不属于 b 的另一组织
						printf("Not sure yet.\n");
					else// a 属于 b 的另一组织
						printf("In different gangs.\n");
				else//a b 属于同一个组织
					printf("In the same gang.\n");
			}
			else
			{
				join_set(a,b+n);//a 属于 b 的另一组织组织
				join_set(b,a+n);//b 属于 a 的另一组织组织
			}
		}
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

温柔说给风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值