poj2492 A Bug's Life

先上题目:

4:A Bug's Life
查看提交统计提问
总时间限制: 10000ms 内存限制: 65536kB
描述
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.
输入
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.
输出
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.
样例输入
2
3 3
1 2
2 3
1 3
4 2
1 2
3 4
样例输出
Scenario #1:
Suspicious bugs found!

Scenario #2:
No suspicious bugs found!
提示
Huge input,scanf is recommended.
来源
TUD Programming Contest 2005, Darmstadt, Germany

  1. 依然是并查集的应用之带关系的并查集,是poj1182的简化版本:不同于poj1182中儿子与父亲结点之间存在三种关系(同类0、父吃子1、子吃父2),此题中儿子与父亲结点之间只有两种关系(同性0、异性1)。
  2. 初始状态时所有的结点都在不同的树中,所有结点的r[]值都为0。如果题目给出的数据能cover所有结点,那么最后的状态必然是只有一棵树,n-1个结点(儿子)指向同一个根(父亲),它们的r[]值各异(依赖于与父亲的关系。当然,是更新过的)。这一整棵树的根结点就是最初合并的两个结点之一
  3. 输入的两个结点先分别执行find,若在一棵树中,以根结点为参照判断它们是否为同性。
  4. 接3,若不在一棵树中,则合并。合并时默认x与y是异性(异性“名额”先到先得),有(fy-->fx)=(fy-->y)+(y-->x)+(x-->fx),即r[fy]=(2-r[y] +1 + r[x])%2。
  5. 若仍有疑问,请看我对poj1182的详细分析:poj1182 食物链,并查集,向量,可能是史上关于此题最清晰易懂的题解

代码清单
#include <cstdio>

#define MAXN 2010

int p[MAXN];	//储存结点的父亲信息
int r[MAXN];	//储存与父亲结点的关系:0同性,1异性

void init(int n)
{
	int i;
	for (i=0; i<=n; ++i)
	{
		p[i]=i;	//初始时所有结点的父亲是它自己
		r[i]=0;	//初始时所有结点与其父亲(也就是它自己)同性
	}
}

int find(int x)
{
	if(x==p[x]) return x;	//路径的最末端,父亲就是它自己

	//否则递归查找
	int t=p[x];
	p[x]=find(p[x]);	//回溯时将所有结点都指向始祖
	r[x]=(r[x]+r[t])%2;	//回溯时更新与新的父结点(即始祖)的关系

	return p[x];
}

//1.union只在find(x)!=find(y)时候做
//2.union的时候默认x与y是异性---其实是一个构建过程,异性“名额”先到先得
//3.把fy嫁接到fx上,并更新关系
void Union(int x, int y)
{
	int fx=find(x);
	int fy=find(y);

	p[fy]=fx;
	r[fy]=(2-r[y] + 1 + r[x])%2;	//中间的1意味着默认x与y是异性
}

int main()
{
	//freopen("D:\\in.txt", "r", stdin);
	//freopen("D:\\out.txt", "w", stdout);

	int t, i, n, k, x, y, j, homo;

	scanf("%d", &t);

	for (i=0; i<t; ++i)
	{
		scanf("%d%d", &n, &k);

		init(n);	//初始化
		homo=0;

		for (j=0; j<k; ++j)
		{
			scanf("%d%d", &x, &y);
			if(find(x)==find(y))	//x,y已经在同一棵树中,那么判断x,y是否为同性
			{
				if( (r[x]+2-r[y])%2 == 0 )	//x和y是同性
					homo=1;
				else
					continue;	//是异性就继续
			}
			else	//若x,y不在一棵树中,默认它们是异性(所谓异性名额先到先得)
				Union(x, y);
		}

		printf("Scenario #%d:\n", i+1);
		if (homo)
			printf("Suspicious bugs found!\n\n");
		else
			printf("No suspicious bugs found!\n\n");
	}

	return 0;
}



你可能感兴趣的:(向量,poj2492,带关系的并查集,并查集拓展,并查集应用)