2-臭虫也疯狂(并查集)

A Bug's Life
Time Limit: 10000MS   Memory Limit: 65536K
Total Submissions: 40402   Accepted: 13171

Descriptionios

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.

Outputide

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 Inputspa

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

Sample Output.net

Scenario #1:
Suspicious bugs found!

Scenario #2:
No suspicious bugs found!

Hintcode

Huge input,scanf is recommended.

Sourceorm

TUD Programming Contest 2005, Darmstadt, Germany
方法一:
224K 719MS
#include <iostream>
#include <cstdio>
using namespace std;
int father[2005];
int rea[2005];

int find(int a){         //并查集 
	int i = a;
	while(father[i] != i){      
		i = father[i];
	}
	int j = a, r;
	if(i != j){
		while(father[j] != i){	//压缩 
			r = father[j];
			father[j] = i;
			j = r;
		}
	}
	return i;
}
void mix(int x, int y){      //匹配 
	int fx = find(x), fy = find(y);
	if(fx != fy)
		father[fx] = fy;
}
int main(){
	int t, m, n, a, b;
	int fa, fb, flag = 1, ct = 0;
	cin >> t;
	
	while(t--){
		ct++;
		flag = 1;
		cin >> m >> n;
		for(int i = 0; i <= m; i++){
			father[i] = i;
			rea[i] = 0;
		}
		for(int i = 0; i < n; i++){
			scanf("%d%d", &a, &b);
			if(flag){
				fa = find(a);
				fb = find(b);
				if(fa == fb){
					flag = 0;
				}
				else if(rea[fa] && rea[fb]){
//					father[rea[fa]] = fb;  //这样直接赋值会破坏压缩的树状数组 
//					father[rea[fb]] = fa;
					mix(rea[fa], fb);   //不能直接像上面那样直接配对,要查寻到父节点在匹配 
					mix(rea[fb], fa); 
				}
				else if(rea[fa] && rea[fb] == 0){
//					father[rea[fa]] = fb;
					rea[fb] = fa;
					mix(rea[fa], fb);
				}
				else if(rea[fa] == 0 && rea[fb]){
//					father[rea[fb]] = fa;
					rea[fa] = fb; 
					mix(rea[fb], fa);
				}
				else if(rea[fa] == 0 && rea[fb] == 0){
					rea[fa] = fb;
					rea[fb] = fa;
				}
			}
		}
		if(flag){
			printf("Scenario #%d:\n", ct);
			printf("No suspicious bugs found!\n\n");
		}
		else{
			printf("Scenario #%d:\n", ct);
			printf("Suspicious bugs found!\n\n");
		}
	}
	return 0; 
}

  方法二:http://blog.csdn.net/i_want_to_be_a_god/article/details/38379281blog

大体题意为:ip

给定n个bugs,编号依次一、二、……n。它们之间只有雄性和雌性之分,并给定m对交配的状况,根据这m对交配的状况,判断是否有同性恋出现的状况。如有则输出“No suspicious bugs found!”不然输出“Suspicious bugs found!”;ci

题目意思很明确了。并且题型也很清晰,典型的循环路径并查集。分析以下:

这里令0表示雄性,1表示雌性(这里0和1只不过表示两种对立的状态,并无具体的含义,能够理解为要么是雄性,要么是雌性)。给每个bug初始化deep为0,即均为雄性或雌性(深度deep表示bug的相对性别关系)。如今解释一下deep如何表示性别的相对关系:

假设A匹配B,可令deep[A]=0,deep[B]=1。如今又有B与C匹配,那么deep[B]=1,deep[C]应该为0才对。这样的话,咱们能够将具备关系的bug并在同一集合中,并用模2方式来循环表示bug之间的相对性别关系。

那么假设有匹配A B,这里就有两种状况了。

1)A与B已经有了关系,即在同一个关系集合中,分两种状况讨论:

  这里deep表示bug之间的相对性别关系,

   11)若A的深度deep与B的深度不一样(即一个为0,一个为1),则说明不是同性恋,继续输入关系

   12)若A的深度deep与B的深度相同(即均为0或均为1),则说明是相同性别,为同性恋关系,已可断定结果,后续只需输入关系便可,无需继续断定

2)A与B尚未关系(即再也不同一关系集合中),状况要复杂一些

因为A与B尚未关系,因此到目前为止是没法判定这个关系是错误的,因此认为这个关系正确(显然)。那么接下来的问题就是:如何将这两个关系和并成一个关系,而且还bug之间的相对性别关系在合并后仍然正确?这就是本题的难点。

分析以下: 假设A 与 B 匹配,A在以X为父节点的关系中,B在以Y为父节点的关系中。咱们能够推到以下:

deep[A]=a(A与父节点X的相对性别关系为a),因为B与A匹配,那么若将B并在以X为父节点的关系中,则deep[B]=(deep[A]+1)%2。而B在以Y为父节点的关系中的深度为b(即B相对Y的性别关系为b,一样Y相对B的性别关系也为b)。这样若将B并在X关系中,那么Y的深度应该为deep[Y]= ((dee[A]+1)%2+deep[b])%2;这样之后,将Y指向X。咱们能够验证一下这样之后是否B与A的相别是相反的即deep[B]=(deep[A]+1)%2;

上述操做之后:deep[B]=(deep[b]+deep[Y])%2,而deep[Y]= ((dee[A]+1)%2+deep[b])%2,带入后可得deep[B]=(deep[A]+1)%2(容易证实)即关系正确。

另外本题还要注意一点:最后结果的输出注意首字母要大写,我就贡献了一次WA。

下面是代码: 180K+719MS

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Max 2010
int deep[Max]; //深度关系
int set[Max]; //并查集
int Case,n,m;
int find(int x){ // 查
	if(set[x]==x) //若循环到父节点,返回父节点标号
		return x;
	int temp=find(set[x]); //查找路径上一个节点
	deep[x]=(deep[set[x]]+deep[x])%2; // 路径更新
	set[x]=temp; //路径压缩
	return temp; //返回父节点
}
int main(){
    scanf("%d",&Case);
	for(int i=1;i<=Case;i++){
		scanf("%d%d",&n,&m);
		memset(deep,0,sizeof(deep)); //初始化为全0
		for(int j=1;j<=n;j++) // 初始化为其自身
			set[j]=j;
		bool trag=true; //设置标记为没有同性恋
		int a,b;
		while(m--){ 
			if(trag){
				scanf("%d%d",&a,&b);
				int x=find(a);
				int y=find(b);
				if(x==y){  //若在同一关系集合中
					if(deep[a]==deep[b]) //若性别相同,则说明是同性恋,不然不是同性恋,正常
						trag=false; //置标记为false
				}
				else{  //再也不同一关系集合中,则必定正确,但要正确和并
					if(x<y){ // 将标号大的并向标号小的
						deep[y]=((deep[a]+1)%2+deep[b])%2; //改变父节点深度
						set[y]=x; //大并小
					}
					else{ //同上
						deep[x]=((deep[b]+1)%2+deep[a])%2;
						set[x]=y;
					}
				}
			}
			else //若已经断定是同性恋关系,则不予判断,直接输入便可
				scanf("%d%d",&a,&b);
		}
		if(trag) //输出,注意首字母大小写
			printf("Scenario #%d:\nNo suspicious bugs found!\n\n",i);
		else
			printf("Scenario #%d:\nSuspicious bugs found!\n\n",i);
	}
	return 0;
}
相关文章
相关标签/搜索