LCA算法_普通做法&倍增&Tarjan&RMQ

末鹿安然 提交于 2019-11-27 16:36:23

题目:POJ-1330

题目大意:给你一棵含有n个结点的树,n-1条边,问两个结点的最近公共祖先是哪个节点。

 

普通做法

思路:让两个结点到达同一深度,再一起往上走,到达同一结点即为最近公共祖先。

           例:3和7,让3往上走到16,与7同一深度后,再一起一步步往上走,到达4时,为同一个结点,即为其最近公共祖先。

 

基本步骤:1、邻接表存图(这里用到的是vector)

                  2、dfs出各个结点的深度

                  3、让深度较高的往上走,走到同一深度

                  4、两个结点一起往上走,走到同一个结点并输出

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 using namespace std;
 5 
 6 const int maxn=10005;
 7 vector<int> son[maxn];
 8 int n;
 9 int p[maxn],in[maxn],dep[maxn];
10 
11 //dfs获取结点深度 
12 void dfs(int root,int depth){
13     dep[root]=depth;
14     for(int i=0;i<son[root].size();i++){
15         p[son[root][i]]=root;
16         dfs(son[root][i],depth+1);
17     }
18     return;
19 }
20 
21 //LCA普通做法核心步骤
22 int LCA(int u,int v){
23     while(dep[u]>dep[v]) u=p[u];
24     while(dep[v]>dep[u]) v=p[v];
25     while(u!=v){
26         u=p[u];
27         v=p[v];
28     }
29     return u;
30 } 
31 
32 int main(){
33     int T,a,b,u,v;//T个测试样例
34     scanf("%d",&T);
35     while(T--){
36         scanf("%d",&n);
37         for(int i=1;i<=n;i++)
38             son[i].clear();
39         memset(in,0,sizeof(in));
40         for(int i=1;i<n;i++){
41             scanf("%d%d",&a,&b);
42             son[a].push_back(b);
43             //代表b是父结点的个数 
44             in[b]++; 
45         }
46         memset(dep,0,sizeof(dep));
47         int root=0;
48         for(int i=1;i<=n;i++)
49             if(in[i]==0) root=i;
50         p[root]=0;
51         dfs(root,0);
52         scanf("%d%d",&u,&v);
53         printf("%d\n",LCA(u,v));
54     } 
55     return 0;
56 } 
57 
58 /*
59 1
60 16
61 1 14
62 8 5
63 10 16
64 5 9
65 4 6
66 8 4
67 4 10
68 1 13
69 6 15
70 10 11
71 6 7
72 10 2
73 16 3
74 8 1
75 16 12
76 16 7
77 */

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!