多叉樹最近公共祖先問題(LCA)
阿新 • • 發佈:2019-02-13
任務:設計一個演算法,對於給定的樹中兩結點,返回它們的最近公共祖先
輸入:第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; }