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;
}
相關文章
相關標籤/搜索