POJ 1703 Find them, Catch them(并查集高级应用)

URL: http://poj.org/problem?id=1703


题目大意:

本题即很经典的“龙帮虎帮”问题。有n个元素(n<=1e5),分布在两个不同的集合里。现在有M个语句(m<=1e5),每个语句共两种:

(1) 给定某两个元素在不同的集合中。

(2) 询问两个元素是否在同一集合中。对于是、否、无法确定的情况,分别输出"In the same gang.", "In different gangs.", "Not sure yet."


思路分析:

假如给定的是两个元素在同一集合中,思路就很明确了。但是现在给定的是两个元素不同集合,而且已知仅有两个集合,于是我们就可以想办法将其转化为两元素同集合问题。

设有元素A,B, 则我们将每个元素分别“克隆”为A', B', 但将她们放入分别与本身不同的另外一个集合中。 

同时,保证A和A', B和B', ...,  永远不会同集合。

然后,假如已知A与B不同集合,则需将A和B', B和A'分别放入同一集合(union操作),假如已知A与B同集合,则需把A和B, A'和B'进行union一下即可。

最后,回答询问时,有以下三种情况:

(1) A与B同集合,或A'与B‘同集合:In the same gang.

(2) A与B'同集合,或B与A'同集合:In different gangs.

(3) 其他:Not sure yet.


代码呈现:

(Time:532MS ,Memory:960K ,Code:1005B)

#include<cstdio>
using namespace std;

const int MAXN = 1e5;
int fa[MAXN*2+2];
int n,m;

int find_fa(int u)
{
    int i,j,k;
    
    i = u;
    while(fa[i] != i)
    {
        i = fa[i];
    }
	fa[u] = i;
	j = u;
	while(j != i)
	{
		k = fa[j];
		fa[j] = i;
		j = k;
	}
    return i;
}

int main()
{
	int i,t,p,q,pp,qq,x,y;
	char ch[3];
	
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		for(i=1; i<=2*n; i++) //Union-Find Sets init
		{
			fa[i] = i;
		}
		for(i=1; i<=m; i++) //calculate while reading
		{
			scanf("%s%d%d",ch,&x,&y);
			if(ch[0] == 'A')
			{
				p = find_fa(x);
				q = find_fa(y);
				pp = find_fa(x+n);
				qq = find_fa(y+n);
				if(p == q) printf("In the same gang.\n");
				else if(pp == q || p == qq) printf("In different gangs.\n");
				else printf("Not sure yet.\n");
			}
			else if(ch[0] == 'D')
			{
				p = find_fa(x);
				q = find_fa(y);
				pp = find_fa(x+n);
				qq = find_fa(y+n);
				if(pp != q) fa[pp] = q;
				if(qq != p) fa[qq] = p;
			}
		}
	}
	
	return 0;
}


类似题目:

poj 2492 A Bug's Life (几乎一模一样)

poj 1182 && luogu P2024 [NOI 2001]食物链 (一样的思路,元素分成三类)

luogu P1525 [NOIP 2010提高组] 关押罪犯 (个人认为难度较大)

猜你喜欢

转载自blog.csdn.net/suncongbo/article/details/76735893
今日推荐