POJ2492 并查集的拓展

前一段时间学了简单的并查集,网上逛技术博客,看到并查集的拓展,在原有并查集的基础上,加入集合内部元素和其父节点之间的关系,这样的拓展,可以解决更多问题

题目链接:

http://poj.org/problem?id=2492

题目大意:

输入n个bug,bug之间有interaction,当前假设异性之间才interaction,但是需要验证,给定这些interaction对,判定是否满足假设

如果男<->女和女<->男,满足条件,如果存在男<->男或者女<->女,则假设不满足

方法:

采用并查集拓展,加入relations[]数组,其中relations[x]表示x和父节点关系,relations[x] = 0表示x和父节点关系为同性,relations[x] = 1表示x和父节点关系为异性

代码如下:

#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;

#define MAX 5005
int parent[MAX];	//记录父节点
int relations[MAX];	//relations[x]记录x和父节点之间的关系
//其中relations[x] = 0表示x和父节点关系为同性, relations[x] = 1表示x和父节点关系为异性

//集合查找
int findSet(int x)
{
	int temp = parent[x];
	if(temp == x)
		return x;

	parent[x] = findSet(temp);
	relations[x] = (relations[x] + relations[temp]) % 2;	//根据老的父节点和新父节点关系,修改relations[x]值

	return parent[x];
}

//合并集合
void unionSet(int root1, int root2)
{
	int x = findSet(root1);
	int y = findSet(root2);

	if(x == y)
		return ;

	parent[x] = y;
	relations[x] = ((relations[root1] - relations[root2] + 1) % 2);
	return ;
}

//初始化数据
void init(void)
{
	memset(relations, 0, sizeof(relations));
	for(int i = 0; i < MAX; i++)
		parent[i] = i;

	return ;
}


int main()
{
	int temp1, temp2;
	int n, m;
	int num;
	int count = 1;

	scanf("%d", &num);
	while(num--)
	{
		scanf("%d%d", &n, &m);
		init();
		int flag = 1;
		for(int i = 0; i < m; i++)
		{
			scanf("%d%d", &temp1, &temp2);
			if(findSet(temp1) == findSet(temp2))
			{
				if(relations[temp1] != (relations[temp2] + 1) % 2)	//如果不满足异性关系,有矛盾
					flag = 0;
			}
			else
			{
				unionSet(temp1, temp2);
			}
		}
		if(flag)
		{
			printf("Scenario #%d:\nNo suspicious bugs found!\n\n", count++);
		}
		else
		{
			printf("Scenario #%d:\nSuspicious bugs found!\n\n", count++);
		}
	}

	return 0;
}




你可能感兴趣的:(bugs)