1. 程式人生 > >hdu1272 小希的迷宮 (並查集)

hdu1272 小希的迷宮 (並查集)

小希的迷宮


上次Gardon的迷宮城堡小希玩了很久(見Problem B),現在她也想設計一個迷宮讓Gardon來走。但是她設計迷宮的思路不一樣,首先她認為所有的通道都應該是雙向連通的,就是說如果有一個通道連通了房間A和B,那麼既可以通過它從房間A走到房間B,也可以通過它從房間B走到房間A,為了提高難度,小希希望任意兩個房間有且僅有一條路徑可以相通(除非走了回頭路)。小希現在把她的設計圖給你,讓你幫忙判斷她的設計圖是否符合她的設計思路。比如下面的例子,前兩個是符合條件的,但是最後一個卻有兩種方法從5到達8。


Input輸入包含多組資料,每組資料是一個以0 0結尾的整數對列表,表示了一條通道連線的兩個房間的編號。房間的編號至少為1,且不超過100000。每兩組資料之間有一個空行。
整個檔案以兩個-1結尾。

Output對於輸入的每一組資料,輸出僅包括一行。如果該迷宮符合小希的思路,那麼輸出"Yes",否則輸出"No"。

Sample Input6 8 5 3 5 2 6 4 5 6 0 0 8 1 7 3 6 2 8 9 7 5 7 4 7 8 7 6 0 0 3 8 6 8 6 4 5 3 5 6 5 2 0 0 -1 -1
Sample OutputYes Yes No

思路:

此題主要判斷兩點:1.是否成環,2.是否有一個以上的樹。滿足以上兩點的任意一點均不能滿足題目要求。

成環判斷:若在兩數相連線前面,他們的幹節點相同,則連線後成環

樹數量判斷:普通並查集

程式碼:

#include<stdio.h>
#include<memory.h>
int pre[100001],v[100001],u[100001];
bool a[100001];
int find(int x){
	int r=x;
	while(pre[r]!=r){
		r=pre[r];
	}
	int i=x,j;
	while(pre[i]!=r){	//壓縮路徑 
		j=pre[i];
		pre[i]=r;
		i=j;
	}
	return r;
}
int main(){
	int i,sum,num,flag;
	while(scanf("%d%d",&v[0],&u[0]) && (v[0]!=-1 && u[0]!=-1)){
		if(v[0]==0 && u[0]==0){
			printf("Yes\n");
			continue;
		}
		memset(a,0,sizeof(a));
		memset(pre,0,sizeof(pre));
		num=1;
		for(i=1;;i++){
			scanf("%d%d",&v[i],&u[i]);
			if(v[i]==0 && u[i]==0)	break;
			a[v[i]]=1,a[u[i]]=1;	//標識出現的數,以備找出未連線前一共有多少總結點 
			num++;	//記錄連線的次數 
		}
		sum=0;
		for(i=0;i<100001;i++){
			if(a[i]==1){
				sum++;	//找到總節點數
				pre[i]=i;	//初始化 
			}
		}
		flag=0;
		for(i=0;i<num;i++){
			if(find(v[i])!=find(u[i])){
				pre[find(u[i])]=find(v[i]);	//連線 
				sum--;
			}
			else{	//兩數有相同的總節點,連線後打通了,成環 
				printf("No\n");
				flag=1;
				break;
			}
		}
		if(flag)	continue;
		if(sum>1){ 
			printf("No\n");
			continue;
		}
		printf("Yes\n");
		
	}
	return 0;
}