1. 程式人生 > >poj 2492 A Bug's Life(並查集)分組並查集

poj 2492 A Bug's Life(並查集)分組並查集

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

Description

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.

Source

題目大意尋找同性戀者。即是出現相同的父節點的時候,說明兩者有同性關係。 巧妙地運用了opp陣列進行標記! 程式碼如下:
#include<stdio.h>
int father[1000010],opp[1000010];//opp[x]=y;表示x的對立面是y,即x與y異性
int find(int x)
{
	return x==father[x]?x:find(father[x]);
}
void merge(int a,int b)
{
	int fa=find(a);
	int fb=find(b);
	if(fa!=fb)
	father[fa]=fb;
}
int main()
{
	int n,i,cnt=1,sum1,sum2;
	scanf("%d",&n);
	while(n--)
	{
	//	memset(father,0,sizeof(father));
		scanf("%d%d",&sum1,&sum2);
		for(i=0;i<=sum1;++i)
		{
			father[i]=i;
			opp[i]=0;
		}
		int x,y,flag=0;
		for(i=0;i<sum2;++i)
		{
			scanf("%d%d",&x,&y);
			if(flag)
			continue;
			if(father[x]==father[y])//相同父節點
			flag=1;
			if(opp[x]==0&&opp[y]==0)
			{
				opp[x]=y;
				opp[y]=x;
			}
			else if(opp[x]==0)
			{
				opp[x]=y;//此時,x的對立面是y,之後繼續合併x,與y的對立面。
				merge(x,opp[y]);
			}
			else if(opp[y]==0)
			{
				opp[y]=x;
				merge(y,opp[x]);
			}
			else 
			{
				merge(opp[x],y);
				merge(x,opp[y]);
			}
		}
		printf("Scenario #%d:\n",cnt++);
		if(flag)
		printf("Suspicious bugs found!\n");
		else
		printf("No suspicious bugs found!\n");
		puts(""); 
	}
	return 0;
} 

方法二:分組並查集(要用C++提交,用G++) 程式碼如下;
#include<stdio.h>
#include<string.h>
int father[1000010];
int find(int x)
{
	return x==father[x]?x:find(father[x]);//資料較小的時候使用遞迴的寫法
}
void merge(int a,int b)
{
	int fa=find(a);
	int fb=find(b);
	if(fa!=fb)
	father[fa]=fb;
}
int main()
{
	int k,count,n,m;
	scanf("%d",&count);
	for(k=1;k<=count;k++)
	{
		scanf("%d%d",&n,&m);
		int flag=0,i;
		for(i=1;i<=n*2;++i)
		father[i]=i;
		for(i=0;i<m;++i)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			merge(x,y+n);//將y+n賦值給x,
			merge(y,x+n);
//			if(flag)
//			continue;
			if(find(x)==find(x+n)||find(y)==find(y+n))//兩者父節點相同,
			flag=1;
		}
		printf("Scenario #%d:\n",k);
		if(flag)
		printf("Suspicious bugs found!\n");
		else
		printf("No suspicious bugs found!\n");
		puts("");
	}
	return 0;	
}

優化之後的演算法:
#include<stdio.h>
#include<string.h>
int father[1000010];
int find(int x)
{
	int r=x;
	while(r!=father[r])
	r=father[r];//迴圈完之後 r表示的就是x的父節點 
	int j;
	j=x;//壓縮路徑 
	while(j!=r)//一直迴圈直至找到最終的父節點 
	{
		int k=father[j];//查詢當前節點的父節點 
		father[j]=r;//將途中經歷的所有的節點的父節點都賦值為總的根節點 
		j=k; //向上迴圈 
	} 
	return r;
}
void merge(int a,int b)
{
	int fa=find(a);
	int fb=find(b);
	if(fa!=fb)
	father[fa]=fb;
}
int main()
{
	int k,count,n,m;
	scanf("%d",&count);
	for(k=1;k<=count;k++)
	{
		scanf("%d%d",&n,&m);
		int flag=0,i;
		for(i=1;i<=n*2;++i)
		father[i]=i;
		for(i=0;i<m;++i)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			merge(x,y+n);
			merge(y,x+n);
			if(flag)
			continue;
			if(find(x)==find(x+n)||find(y)==find(y+n))
			flag=1;
		}
		printf("Scenario #%d:\n",k);
		if(flag)
		printf("Suspicious bugs found!\n");
		else
		printf("No suspicious bugs found!\n");
		puts("");
	}
	return 0;	
}