HDU 1829 扩展并查集

http://acm.hdu.edu.cn/showproblem.php?pid=1829

Background
Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they feature two different genders and that they only interact with bugs of the opposite gender. In his experiment, individual bugs and their interactions were easy to identify, because numbers were printed on their backs.

Problem
Given a list of bug interactions, decide whether the experiment supports his assumption of two genders with no homosexual bugs or if it contains some bug interactions that falsify it.

Input

The first line of the input contains the number of scenarios. Each scenario starts with one line giving the number of bugs (at least one, and up to 2000) and the number of interactions (up to 1000000) separated by a single space. In the following lines, each interaction is given in the form of two distinct bug numbers separated by a single space. Bugs are numbered consecutively starting from one.

Output

The output for every scenario is a line containing "Scenario #i:", where i is the number of the scenario starting at 1, followed by one line saying either "No suspicious bugs found!" if the experiment is consistent with his assumption about the bugs' sexual behavior, or "Suspicious bugs found!" if Professor Hopper's assumption is definitely wrong.

Sample Input

2
3 3
1 2
2 3
1 3
4 2
1 2
3 4

Sample Output

Scenario #1:
Suspicious bugs found!

Scenario #2:
No suspicious bugs found!


        
  

Hint

Huge input,scanf is recommended.

题目大意:一种昆虫,有两种性别,只有不同性别的昆虫才能放在一起,现在有n只昆虫,标号为1-n,输入m对昆虫,让你判断有没有不合题意的情况。即有没有出现矛盾,优先认为最开始输入的是正确的。

思路:博主也是第一次做这种题目,初次入手感觉好难啊,如有不对的地方,欢迎提出~下面这篇博客也给我提供了帮助~

http://www.cnblogs.com/xzxl/p/7341536.html

解这种题目需要一个关系数组relation,relation[i]表示第i个结点与其根结点的关系,注意是与根结点的关系,理解这一点是很重要的。我们用relation[i]=0表示i与根结点的昆虫同性relation[i]=1表示i与根结点的昆虫异性。那么初始化时自然要全部置为0,认为每个昆虫都是独立的个体,自己跟自己肯定是同性的。这个关系数组有什么用呢?设想一下,出现了矛盾的情况,必然是A与B异性,B与C异性,因为性别只有两种,那么A与C必定是同性的,然而后面却把AC放在了一起,这是不合题意的。而这时候的关系,跟并查集的操作有很大的关联性!首先A、B异性,我们假设B是根节点,那么relation[A]=1,代表A与B异性,然后又告诉了我们B与C异性,那么relation[C]=1,代表B与C同性,后面又说A与C是同性的,然而A与C有相同的根结点,我们又知道关系数组的值,自然可以推出矛盾。这时relation[A]+relation[C]=2,我们先放在这不管,再考虑另外一种情况:A是根结点,B与A异性,然后该诉你C、D都与B异性,那么relation[C]=relation[D]=0,代表C、D与A同性。这时候再把C、D放在一起,我们知道这也是不合理的。综上,不合理的情况就是:昆虫A与昆虫B在同一个集合中,但是(relation[A]+relation[B])%2==0!有了这个结论,判断是否有矛盾的操作是不是就简单多了!但是还有几个难点,就是如何在Find操作和Union操作中修改关系数组的值呢?既然relation数组记录的是当前结点根结点的关系,那么在知道父节点根结点关系的基础上,在压缩路径的时候,即把当前结点接到根结点上的时候,我们就可以确定当前结点relation该怎么修改了!下图的情况就是A、B之前已经连到一起了,然后又把它们与C连到了一起,这时候查询A的根结点的时候,就需要路径压缩的操作,注意此时relation[A]表示的是A与B的关系:(就是已知B、C关系 已知A、B关系 把A接到C上的时候 怎么修改relation[A])

注:为什么relation[A]表示的是A与B的关系呢?仔细想一下在下面左图的情况下,relation[A]可能表示的A与C的关系吗?肯定是不可能的,如果表示的是A与C的关系,那么必定是在合并操作的时候直接把A指向C了,而不是左图的情况。

  A 与结点B关系 B 与结点C关系 A 与结点C关系
relation 0              同性 0 同性 0 同性
relation 0 同性 1 异性 1 异性
relation 1 异性 0 同性 1 异性
relation 1 异性 1 异性 0 同性

观察表格就可以得到:relation[A]=(relation[A]+relation[B])%2

这个操作在Find里面是不是很容易实现呢?!那么问题只剩下了Union里面relation的修改了!这里我推荐用向量的方式来思考!(能想到的真的是大佬orz)A、C,B、D关系如下,下面给出C和D的关系,那么我们肯定要把A、C、B、D都合并起来,假设令B指向A,那么怎么修改lelation[B]的值呢?(并不用修改子节点的值哦 那个会在Find里面完成的~)

C->A:relation[C]       C->D:1        D->B:relation[D](既然C、D能放到一起 那肯定是异性 所以中间那个值为1!)

那么根据向量的加法:A->B=A->C+C->D+D->B

relation[A]=(-relation[C]+1+relation[D])%2

可以验证一下结果是成立的!(C与D是异性的)

  C C与A关系 D D与B关系 B B与A关系
relation 0 同性 0 同性 1 异性
relation 0 同性 1 异性 0 同性
relation 1 异性 0 同性 0 同性
relation 1 异性 1 异性 1 异性

有了上面的结论,这道题就可以做出来了~

#include<iostream>
#include<cstdio>
#include<stack>
#include<cmath>
#include<cstring>
#include<queue>
#include<set>
#include<algorithm>
#include<iterator>
#define INF 0x3f3f3f3f
typedef long long ll;
typedef unsigned long long ull;
using namespace std;

					//考虑与根结点的关系是关键!
					//根结点的relation 等于0
int f[2005];
int relation[2005];
int n,m;

void init()
{
	for(int i=1;i<=n;i++)
	{
		f[i]=i;
		relation[i]=0;
	}
}

int Find(int x)
{
	if(f[x]==x)
		return x;
	int temp=f[x];
	f[x]=Find(f[x]);
	relation[x]=(relation[x]+relation[temp])%2;
	return f[x];
}

int Union(int x,int y)
{
	int fx=Find(x),fy=Find(y);
	if(fx!=fy)
	{
		f[fx]=fy;
		relation[fx]=(-relation[x]+1+relation[y])%2;
	}
	else	//同根
	{
		if((relation[x]+relation[y])%2==0)
			return 0;
		else
			return 1;
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	int times=0;
	while(t--)
	{
		scanf("%d%d",&n,&m);
		init();
		int t1,t2;
		int flag=0;
		for(int i=0;i<m;i++)
		{
			scanf("%d%d",&t1,&t2);
			if(!Union(t1,t2))
				flag=1;
		}
		if(flag)
			printf("Scenario #%d:\nSuspicious bugs found!\n",++times);
		else
			printf("Scenario #%d:\nNo suspicious bugs found!\n",++times);
		printf("\n");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xiji333/article/details/86650735