poj1703 犯罪团伙 并查集

      在讲解这个题目之前, 我不得不狠狠的吐槽cin和cout的效率, 我提交了6遍都是超时, 最后一遍提交时统统把cin和cout改为scanf和printf才过的, 当时心情又高兴又难受.

   查看题目点击这里 Find them, Catch them POJ - 1703

吐槽完了, 开始讲题.

       第一次遇见这种题目是感觉满头痛的, 咦~, 并查集不是将关系是朋友的联系在一起吗? 可没学过把敌人分开的呀! (题目是我在并查集专题遇见的, 所以一开始我知道是要并查集的).

       是的 , 我们没学过将敌人分开, 但可以转化思路, 正所谓敌人的敌人就是朋友, 我们可以将a和 b的敌人结为朋友不就化成我们平时所熟悉的题型了吗 (因为只有两大帮派, 所以不是朋友就是敌人)( enemy[b]指的就是b的敌人)

      在这里就不讲解并查集的原理了, 默认大家都会并查集, 如果对并查集不熟, 强烈推荐看看我的另一篇转载的文章, 是讲解并查集的   <有趣的并查集详解>

 

这里就直接附上代码, 解释注释部分够了

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX = (int)1e5 + 5;
int per[MAX],enemy[MAX];

int find(int x)   //查找根节点
{
	int r = x;
	while (r != per[r])
		r = per[r];
	int i = x, j;
	while (i != r)   //压缩路劲, 这段不加上应该没什么大问题
	{
		j = per[i];
		per[i] = r;
		i = j;
	}
	return r;
}
void join(int x, int y) //x,y结成朋友
{
	int fx = find(x), fy = find(y);
	if (fx != fy)
		per[fx] = fy;
}
int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
	{
		int n, m;
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; i++)
		{
			per[i] = i;
			enemy[i] = 0;  //0 代表没有敌人
		}
		//memset(enemy, 0, sizeof(enemy));//0代表没有敌人
		getchar();  //别忘加这个
		while (m--)
		{
			char c;
			int a, b;
			scanf("%c%d%d", &c, &a, &b);
			//cin >>c >> a >> b;
			getchar();  //别忘了加这个
			if (c == 'D')
			{
				if (enemy[a] == 0 && enemy[b] == 0)//如果原来a,b都没有敌人
				{
					enemy[a] = b; enemy[b] = a;//那么现在a,b就是敌人
				}
				else if (enemy[a] == 0) //如果a没有敌人, 而b有敌人
				{
					enemy[a] = b;//那么现在a的敌人就是b;
					join(a, enemy[b]); //a和b是敌人,所以a和b的敌人enemy[b]就是朋友
				}
				else if (enemy[b] == 0) //如果b没有敌人, a有敌人
				{
					enemy[b] = a; //那么现在b的敌人就是a
					join(b, enemy[a]); //b和a是敌人,a和enemy[a]是敌人,所以b和enemy[a]是朋友
				}
				else//a,b都有敌人
				{
					join(a, enemy[b]);
					join(b, enemy[a]);
				}
			}
			else if (c == 'A')
			{
				if (find(a) == find(b)) //如果a,b有相同的根节点,则a,b是朋友
					//cout << "In the same gang." << endl;
					printf("%s\n", "In the same gang.");
				//如果a和b的敌人在一起  或者  b和a的敌人在一起  就认为a,b是敌人 ---- 这里不可以写成 find(a)!=find(b)
				else if (find(a) == find(enemy[b]) || find(b) == find(enemy[a]))
					//cout << "In different gangs." << endl;
					printf("%s\n", "In different gangs.");
				else
					//cout << "Not sure yet." << endl;
					printf("%s\n", "Not sure yet.");
			}
		}
	}
	return 0;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值