标签:des style blog http color io os ar for
Description
Input
Output
Sample Input
2
16
1 14
8 5
10 16
5 9
4 6
8 4
4 10
1 13
6 15
10 11
6 7
10 2
16 3
8 1
16 12
16 7
5
2 3
3 4
3 1
1 5
3 5
Sample Output
4
3
最近在复习一些暑假集训时候学到的一些数据结构,这次的主题是LCA(最近公共祖先),找出一棵树里边任意两个节点的最近公共祖先节点(这个称呼不太科学?),这是一道全裸的LCA的题目,有两种解决思路
方法一:对于每次查询的两个节点,先让两个节点上升到同一个深度的地方,然后两个节点在同时上升,直到两个节点相遇为止,相遇的点即为最近公共祖先。
方法二:先让某个节点一直往上走一直走到根节点,并开一个数组记录这个路径,让后再让另一个节点往上走,直到与前一个节点产生的路径相交为止,那么这个交点也是两个节点的最近公共祖先啦~
方法1的AC代码:
1 /********************************* 2 Author: jusonalien 3 Email : jusonalien@qq.com 4 school: South China Normal University 5 Origin: 6 *********************************/ 7 #include <cstdio> 8 #include <vector> 9 #include <cstring> 10 using namespace std; 11 const int maxn = 11111; 12 vector<int>G[maxn]; 13 int depth[maxn],father[maxn]; 14 int root,n; 15 void dfs(int v,int p,int d){//通过dfs构造出一棵树,并且记录每个节点的深度,这个很重要! 16 depth[v] = d; 17 for(int i = 0;i < G[v].size();++i){ 18 if(G[v][i] != p) dfs(G[v][i],v,d+1); 19 } 20 return ; 21 } 22 int lca(int u,int v){ 23 while(depth[u] > depth[v]) u = father[u]; 24 while(depth[v] > depth[u]) v = father[v]; 25 while(u != v){ 26 u = father[u]; 27 v = father[v]; 28 } 29 return u; 30 } 31 void init(){ 32 memset(depth,0,sizeof(depth)); 33 memset(father,-1,sizeof(father)); 34 for(int i = 1;i <= n;++i) G[i].clear(); 35 } 36 void print(){//调试代码 37 for(int i = 1;i <= n;++i) printf("%02d ",father[i]); 38 puts(""); 39 for(int i = 1;i <= n;++i) printf("%02d ",depth[i]); 40 puts(""); 41 } 42 int main(){ 43 int cas; 44 int a,b; 45 scanf("%d",&cas); 46 while(cas--){ 47 scanf("%d",&n); 48 init(); 49 for(int i = 1;i < n;++i){ 50 scanf("%d%d",&a,&b); 51 father[b] = a; 52 G[a].push_back(b); 53 } 54 for(int i = 1;i <= n;++i) 55 if(father[i] == -1){ 56 root = i;break; 57 } 58 dfs(root,-1,0); 59 //print(); 60 scanf("%d%d",&a,&b); 61 printf("%d\n",lca(a,b)); 62 } 63 return 0; 64 }
方法2的AC代码:
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 int const maxn = 10000+10; 5 int fa[maxn]; 6 bool vis[maxn]; 7 int n; 8 int main() 9 { 10 int T; 11 scanf("%d",&T); 12 while(T--) 13 { 14 int u,v; 15 scanf("%d",&n); 16 memset(vis,0,sizeof(vis)); 17 memset(fa,0,sizeof(fa)); 18 for(int i=1;i<n;++i) 19 { 20 scanf("%d%d",&u,&v); 21 fa[v]=u; 22 } 23 scanf("%d%d",&u,&v); 24 do 25 { 26 vis[u]=true; 27 u=fa[u]; 28 }while(u!=0); 29 do 30 { 31 if(vis[v]) 32 { 33 printf("%d\n",v); 34 break; 35 } 36 v=fa[v]; 37 }while(v!=0); 38 } 39 return 0; 40 }
个人觉得,方法1对于同一棵树上的大规模查询的效率要比方法2要高,并且当查询的节点大都在树的底层的时候,方法2会产生很多不必要的查询,也会产生较多的浪费(并且个人觉得方法1的代码更加优美?
Ps:这里有一份很不错的关于RMQ和LCA的学习资料介绍,请猛戳此处 选自农夫三拳。
标签:des style blog http color io os ar for
原文地址:http://www.cnblogs.com/jusonalien/p/4012376.html