1. 程式人生 > >多叉樹最近公共祖先問題(LCA)

多叉樹最近公共祖先問題(LCA)

任務:設計一個演算法,對於給定的樹中兩結點,返回它們的最近公共祖先

輸入:第1行有一個正整數n,表示給定的樹有n個結點。結點編號為1,2,3,...,n,編號為1的頂點是樹根。接下來n行中,第i+1行描述了第i個結點的兒子情況。每行的第一個正整數k表示該結點有k個兒子,其後k個數中,每一個數表示其兒子結點的編號。當k=0時表示該結點為葉節點。

輸入的第n+2行是一個正整數m,表示要計算最近公共祖先的m個結點對。接下來的m行,每行兩個正整數,前兩個是結點編號,第3個是它們的最近公共祖先結點編號。

輸入樣例:

12

3 2 3 4

2 5 6

0

0

2 7 8

2 9 10

0

0

0

2 11 12

0

0

5

3 11

7 12

4 8

9 12

8 10

輸出樣例:

3 11 1

7 12 2

4 8 1

9 12 6

8 10 2

不會什麼高深的演算法,直接暴力搜尋了。其實還可以稍微優化一下,即儲存路徑時只需要儲存一條,然後讓另一個結點一直回溯,比較判斷就好了。不過想到這個的時候已經寫完了,也沒心思去改了、、、

#include <iostream>
#include <vector>
using namespace std;

typedef struct{
	int parent;
	int *son;
}TreeNode;

void findPath(TreeNode* node, int x, vector<int>& path)
{
	int i;
	//	找出該結點到根結點的路徑
	//	因根結點父節點已標記為0,故以此為迴圈結束條件 
	while( node[x].parent != 0 ){
		i = node[x].parent;
		path.push_back(i);
		x = i;	
	}
}

int find_ClosetParent(vector<int>& path_a, vector<int>& path_b)
{
//	O( path_a.size() * path_b.size() ) 
	for(int i = 0; i < path_a.size(); ++i)
		for(int k = 0; k < path_b.size(); ++k)
			if( path_a[i] == path_b[k] )
				return path_a[i];
				
	return -1;	//	若結點對有一個是根結點,則找不到	
} 

int main()
{	
	int n, m, k, pos;
	while( cin >> n )
	{
		TreeNode node[n+1];
		//	構建樹 
		node[1].parent = 0;	//根結點的父親結點下標標記為0 
		for(int i = 1; i <= n; ++i){
//			cout << "node " << i << endl;
			cin >> k;
			node[i].son = (k!=0) ? (new int[k]):nullptr;	//m為0表示沒有兒子 
			for(int j = 0; j < k; ++j){
				cin >> pos;
				node[pos].parent = i;	//將該兒子結點的父節點標記為當前結點	
				node[i].son[j] = pos;	//儲存該結點的兒子結點下標 
			}
		}
		//	尋找公共祖先結點
		int a, b, res;
		cin >> m;
		while( m-- ){
//			cout << "opt " << endl;
			vector<int> path_a, path_b;
			cin >> a >> b;
			//	加速優化 
			if( a==b || node[a].parent==node[b].parent ){
				res = node[a].parent;
			}else{
				findPath(node, a, path_a);
				findPath(node, b, path_b);
				res = find_ClosetParent(path_a, path_b);
			}
			cout << a << " " << b << " " << res << endl;
		}
		//	釋放node陣列開闢的son陣列空間
		for(int i = 1; i <= n; ++i)
			delete[] node[i].son; 
		cout << "-----END-----" << endl;	
	}
	
	return 0;
}