PAT A1143 Lowest Common Ancestor
第一次遇到LCA,想的比较乱,感觉有点并查集的意思,又好像不行。开始的想法是用BST的性质和前序建树,建树过程中做一个father数组,然后再dfs做一个level数组,之后就可以根据两个数所处的层数进行处理:下层的顺着father数组往上走,直到俩个层数一样,如果此时两个下标相等,说明之前上层那个就是公共祖先;如果不相等,两人同时向上走,直到下标相等,此时就找到了LCA 由于受到BST的诱惑,查找一个数的位置(是否存在)时,甚至还写了二分。。。经过一番折腾,不知道哪个步骤写的不对,最郁闷的是样例都过了,提交只得了1分。。。当时就受到了相当严重的伤害 后来看了几篇博客,发现我这个想法学名叫倍增法,看来道理上没有问题,于是重新用前序中序建树,因为father和level都可以在建树过程中得到,所以只需要一个build就够了,至于查找就直接换成了map,main不做改动,提交居然就过了。。。之前的问题稍后再研究,,,这里也是首次发现建树并不需要四个下标,提供root的序列只传一个root下标就行了 另外发现一个解决LCA的挺好玩的算法叫Tarjan https://www.cnblogs.com/JVxie/p/4854719.html ,本来这么恐怖的名字我是不敢看的,可是一查是个图灵奖得主,就往下看了看。整个有点像dfs+并查集,假设C是A和B的LCA,首先dfs经过C访问到A,此时如果想访问B的话,就一定是在回退到C的基础上再向下找到B,而不可能是回退到其他的顶点。so算法在回退过程中将访问过的节点都标记了visited和father,假设此时访问到B,发现需要找B和A的LCA,那么看一下A是否已经标记过,如果标记过,那么LCA = findfather(A),findfather会找到C点,因为C是目前A向上找father的终点,他还没有向上返回
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
using namespace std;
struct Node{
int data, father, level;
} ;
vector< Node> inorder;
vector< int > preorder;
unordered_map< int , int > umap;
void build ( int root, int inL, int inR, int father, int level) {
if ( inL > inR) return ;
int pos = inL;
while ( inorder[ pos] . data != preorder[ root] ) pos ++ ;
inorder[ pos] . father = father;
inorder[ pos] . level = level;
build ( root + 1 , inL, pos - 1 , pos, level + 1 ) ;
build ( root + 1 + pos - inL, pos + 1 , inR, pos, level + 1 ) ;
}
bool cmp ( Node n1, Node n2) {
return n1. data < n2. data;
}
int main ( ) {
int M, N;
cin >> M >> N;
inorder. resize ( N) ;
preorder. resize ( N) ;
for ( int i = 0 ; i < N; i ++ ) {
cin >> preorder[ i] ;
inorder[ i] . data = preorder[ i] ;
}
sort ( inorder. begin ( ) , inorder. end ( ) , cmp) ;
for ( int i = 0 ; i < N; i ++ ) umap[ inorder[ i] . data] = i + 1 ;
build ( 0 , 0 , N - 1 , - 1 , 0 ) ;
for ( int i = 0 ; i < M; i ++ ) {
int a, b;
cin >> a >> b;
int pos1 = umap[ a] - 1 , pos2 = umap[ b] - 1 ;
if ( pos1 == - 1 && pos2 == - 1 ) printf ( "ERROR: %d and %d are not found.\n" , a, b) ;
else if ( pos1 == - 1 ) printf ( "ERROR: %d is not found.\n" , a) ;
else if ( pos2 == - 1 ) printf ( "ERROR: %d is not found.\n" , b) ;
else {
int lv1 = inorder[ pos1] . level, lv2 = inorder[ pos2] . level;
bool flag = ( lv1 > lv2) ;
while ( lv1 > lv2) {
pos1 = inorder[ pos1] . father;
lv1 -- ;
}
while ( lv2 > lv1) {
pos2 = inorder[ pos2] . father;
lv2 -- ;
}
if ( pos1 == pos2) printf ( "%d is an ancestor of %d.\n" , ( flag ? b : a) , ( flag ? a : b) ) ;
else {
while ( pos1 != pos2) {
pos1 = inorder[ pos1] . father;
pos2 = inorder[ pos2] . father;
}
printf ( "LCA of %d and %d is %d.\n" , a, b, inorder[ pos1] . data) ;
}
}
}
return 0 ;
}