码迷,mamicode.com
首页 > 其他好文 > 详细

用“倍增法”求最近公共祖先(LCA)

时间:2015-07-07 12:57:09      阅读:131      评论:0      收藏:0      [点我收藏+]

标签:


1.最近公共祖先:对于有根树T的两个结点u、v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u、v
的祖先且x的深度尽可能大。
2.朴素算法:记录下每个节点的父亲,使节点u,v一步一步地向上找父亲,直到找到相同的“祖先”,即
是所求的答案,时间复杂度O(n)。
3.优化算法(倍增法):利用二进制的思想,想办法使一步一步向上搜变成以2^k地向上跳。
所以定义一个P[][]数组,使p[i][j]表示节点i的2^j倍祖先,因此p[i][0]即为i的父亲。
我们可以得到一个递推式p[i][j]=p[i][j-1][j-1]。这样子一个O(NlogN)的预处理(dfs)的 2^k 的祖先。
定义一个deep[]数组表示节点深度,
先判断是否 deep[u > deep[v]果是的话就交换一下(保证 u的深度小于 v方便下面的操作)然后把u到与
v同深度,同深度以后再把u v同时往上调(dec(j)) 调到有一个最小的j 满足: p[u] [j]!=p[v][j],u,v
是在不断更新的   最后把u,v 往上调 (u=p[u,0] v=p [v,0]) 一个一个向上调直到   u= v 这时 u or v
就是公共祖先。复杂度:O(logn)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int N,root;
 4 struct node{
 5     int rc,lc,fa,deep; 
 6 };
 7 node tree[2000];
 8 int p[2000][2000];
 9 int a,b;
10 void dfs(int r);
11 int LCA(int,int);
12 int main(){
13     cin>>N;
14     for(int i=1;i<=N-1;i++){
15         int f,c;
16         cin>>f>>c;
17         if(tree[f].lc!=0) tree[f].rc=c;
18         else tree[f].lc=c;
19         tree[c].fa=f;
20         p[c][0]=f;//c的2^0==1,即它的一倍祖先是它父亲 
21     }
22     for(int i=1;i<=N;i++){
23         if(tree[i].fa==0){
24             root=i;
25             break;
26         }
27     }
28     tree[root].deep=1;
29     dfs(root);
30     cin>>a>>b; 
31     cout<<LCA(a,b);
32     
33     return 0;
34 }
35 void dfs(int r){
36     if(r==0) return ; 
37     int ll=tree[r].lc;
38     int rr=tree[r].rc;
39     tree[ll].deep=tree[r].deep+1;
40     tree[rr].deep=tree[r].deep+1;
41     for(int i=1;i<=N;i++){//处理P数组 
42         int zu=1;
43         for(int k=1;k<=i;k++) zu*=2;
44         if(zu<=tree[r].deep)
45         p[r][i]=p[p[r][i-1]][i-1];
46         else break;    
47     }
48     dfs(ll);
49     dfs(rr);
50 }
51 int LCA(int x,int y){
52     if(tree[x].deep<tree[y].deep) swap(x,y);//保证x比y高
53     int delta=tree[x].deep-tree[y].deep;
54     //使x和y移到统一高度 
55     for(int i=0;i<=30;i++){
56         if((1<<i)&delta){//把跳的路径拆成2^k... 
57             x=p[x][i];
58         }
59     }
60     
61     if(x==y) return x;
62     for(int i=N-1;i>=0;i--){
63         if(p[x][i]!=p[y][i]){//保证不一样才跳,防止跳出最近祖先 
64             x=p[x][i];
65             y=p[y][i];
66         }
67     }
68     
69     return p[x][0];//因为不断跳到不一样的节点,所以ans一定是x或y的2^0倍祖先 
70 }

 

用“倍增法”求最近公共祖先(LCA)

标签:

原文地址:http://www.cnblogs.com/CXCXCXC/p/4626591.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!