1. 程式人生 > 實用技巧 >PTA 7-5 有趣的最近公共祖先問題 (30分)

PTA 7-5 有趣的最近公共祖先問題 (30分)

題目描述:

給出一顆二叉樹的後序遍歷和中序遍歷,你能計算出兩個結點的最近公共祖先嗎?

輸入格式:

第一行給出兩個整數N(N<=10000)和M(M<=10000),分別代表二叉樹的結點數和我們接下來的詢問數。

第二行和第三行分別給出N個整數,每個整數用空格分開,分別代表二叉樹的後序遍歷和中序遍歷。

接下來M行,每行給出兩個整數,代表我們要詢問的兩個結點的編號a和b。

輸出格式:

對於每個我們要求的詢問:

1.如果a和b中有一個或兩個不在樹上,輸出"ERROR"。

2.否則在一行中輸出一個整數,表示a和b的最近公共祖先。

輸入樣例:

在這裡給出一組輸入。例如:

3 3
2 3 1
2 1 3
1 2 2 3 0 3

輸出樣例:

在這裡給出相應的輸出。例如:

1
1
ERROR

先講一下思路:這道題最主要的還是怎麼去查詢這個公共祖先的問題, 建樹不是主要的。首先應該把樹建好。接下來是查詢

1、查詢的時候,找到我們要找的結點就直接返回

2、找不到的就返回NULL

3、查詢到最後,返回的是它兩的公共祖先

#include<bits/stdc++.h>
using namespace std;//
typedef struct node {
    int num ;
    struct node * left;
    struct node * right;
}Node;
vector
<int> vec; queue<Node*> q; Node * build(int *zhong , int * hou , int n)/// 建樹 { Node *tree; if(zhong==NULL || hou == NULL || n <= 0) return NULL; int gen = *(hou+n-1); int k = 0; while(*zhong != gen){/// 前序遍歷和中序遍歷 zhong++; k++; } tree = (Node*)malloc
(sizeof(node)); tree->num = gen ; tree->left = build(zhong-k , hou , k); tree->right = build(zhong+1 , hou+k , n-k-1); return tree; } Node* solve(Node * tree , int a , int b )/// 查詢最近的公共祖先 { if (tree == NULL) /// 樹NULL , 說明沒有找到這個結點 return NULL; if(a == tree->num || b == tree->num)/// 當前的這個結點就是要找的結點之一 return tree; Node *t = NULL; Node *left_ = solve(tree->left ,a , b);/// 左右子樹找 Node * right_ = solve(tree->right , a ,b); if(left_ && right_)/// 一個在左子樹,一個在右子樹 , 說明當前的結點就是最近的公共祖先了 return tree; if(left_ == NULL)/// return right_; else return left_; } int main() { int n , m; cin>>n>>m; int zhong[10001] , hou[10001]; bool flog[10001];/// 標記陣列,這個數字出現過了,就 true for(int i = 0; i < n ; i++){ cin>>hou[i]; flog[hou[i]] = true; } for(int i = 0; i < n ; i++) cin>>zhong[i]; Node *tree = build(zhong , hou , n);/// 建樹 vec.push_back(0); for(int i = 0 ; i < m ; i++){ int a , b ; cin>>a>>b; if(!flog[a] || !flog[b]){/// 看這個結點有沒有,沒有就直接continue了 cout<<"ERROR"<<endl; continue; } Node * t = solve(tree , a,b);/// 找 a , b 的最近祖先 , 返回的是最近祖先的結點node cout<<t->num<<endl;/// } return 0; } /* 3 2 2 3 1 2 1 3 1 2 2 3 */