1. 程式人生 > >7-10 樹的同構(25 point(s))

7-10 樹的同構(25 point(s))

給定兩棵樹T1和T2。如果T1可以通過若干次左右孩子互換就變成T2,則我們稱兩棵樹是“同構”的。例如圖1給出的兩棵樹就是同構的,因為我們把其中一棵樹的結點A、B、G的左右孩子互換後,就得到另外一棵樹。而圖2就不是同構的。


圖1


圖2

現給定兩棵樹,請你判斷它們是否是同構的。

輸入格式:

輸入給出2棵二叉樹樹的資訊。對於每棵樹,首先在一行中給出一個非負整數N (10),即該樹的結點數(此時假設結點從0到N1編號);隨後N行,第i行對應編號第i個結點,給出該結點中儲存的1個英文大寫字母、其左孩子結點的編號、右孩子結點的編號。如果孩子結點為空,則在相應位置上給出“-”。給出的資料間用一個空格分隔。注意:題目保證每個結點中儲存的字母是不同的。

輸出格式:

如果兩棵樹是同構的,輸出“Yes”,否則輸出“No”。

輸入樣例1(對應圖1):

8
A 1 2
B 3 4
C 5 -
D - -
E 6 -
G 7 -
F - -
H - -
8
G - 4
B 7 6
F - -
A 5 1
H - -
C 0 -
D - -
E 2 -

輸出樣例1:

Yes

輸入樣例2(對應圖2):

8
B 5 7
F - -
A 0 3
C 6 -
H - -
D - -
G 4 -
E 1 -
8
D 6 -
B 5 -
E - -
H - -
C 0 2
G - 3
F - -
A 1 4

輸出樣例2:

No

code:

#include <stdio.h>
#include <string.h>
struct TNode{
	char Data;//字母 
	int Left,Right;//左右兒子編號 
};//建立樹的結構體 

typedef struct TNode Tree;//typedef簡化名稱 
Tree t1[12],t2[12];//兩棵樹的陣列用於比較 

int Read(Tree t[]){
	int i;
	int n;//節點個數 
	int pre[12];//祖先陣列,用於判斷樹根
	int root = -1;//樹根標號,初始化為-1
	memset(pre,0,sizeof(pre)) ;
	scanf("%d",&n);
	if(n){//如果n不為零執行 
		for(i = 0; i < n; i++){
			char l,r;//記錄左右兒子的值 
			scanf(" %c %c %c",&t[i].Data,&l,&r);
			if(l!='-'){
				t[i].Left = l-'0';//如果是數字,左子樹記錄該數字
				pre[t[i].Left] = 1;//表示這個左孩子編號有父親 
			}
			else{
				t[i].Left = -1;
			}
			if(r!='-'){//右邊同理 
				t[i].Right = r-'0';
				pre[t[i].Right] = 1;
			}
			else{
				t[i].Right = -1;
			}
		} 
	}//記錄完畢
	
	//找根
	for(i = 0; i < n; i++){
		if(!pre[i]){//如果有節點父親是0,說明沒父親為樹根 
			root = i;
			break;
		}
	} 
	return root;
} 

int isSame(int root1,int root2){
	if((root1 == -1) && (root2 == -1)){//樹根都是空,同構返回1 
		return 1;
	}
	
	if(((root1 == -1) && (root2 != -1)) || ((root1 != -1) && (root2 == -1))){//如果一個是空一個不空,不同構,返回0 
		return 0;
	}
	
	if((t1[root1].Data) != (t2[root2].Data)){//如果樹根值不同,不同構,返回0 
		return 0; 
	}
	
	if((t1[root1].Left == -1) && (t2[root2].Left == -1)){//如果左子樹都是空的,判斷右子樹 
		return isSame(t1[root1].Right,t2[root2].Right);
	}
	
	if((t1[root1].Left != -1) && (t2[root2].Left != -1) && (t1[t1[root1].Left].Data == t2[t2[root2].Left].Data)){//如果左樹不空且左子樹值想同,判斷其左右子樹 
		return (isSame(t1[root1].Left,t2[root2].Left) && isSame(t1[root1].Right,t2[root2].Right));
	}
	
    else{//如果左子樹有一個空的,或者兩個樹不空 左子樹的值不同 ,交換左右子樹判斷 
    	return (isSame(t1[root1].Left,t2[root2].Right) && isSame(t1[root1].Right,t2[root2].Left)); 
	}
} 

int main(){
	
	int root1,root2;//樹根節點編號 
	
	root1 = Read(t1);//讀取 
	root2 = Read(t2);
	
    if(isSame(root1,root2))//判斷是否同構 
       printf("Yes\n");
    else
       printf("No\n");
	return 0;
}