【POJ 1330 Nearest Common Ancestors】LCA问题 Tarjan算法

简介: 题目链接:http://poj.org/problem?id=1330 题意:给定一个n个节点的有根树,以及树中的两个节点u,v,求u,v的最近公共祖先。 数据范围:n [2, 10000] 思路:从树根出发进行后序深度优先遍历,设置vis数组实时记录是否已被访问。

题目链接:http://poj.org/problem?id=1330

题意:给定一个n个节点的有根树,以及树中的两个节点u,v,求u,v的最近公共祖先。

数据范围:n [2, 10000]

思路:从树根出发进行后序深度优先遍历,设置vis数组实时记录是否已被访问。

每遍历完一棵子树r,把它并入以r的父节点p为代表元的集合。这时判断p是不是所要求的u, v节点之一,如果r==u,且v已访问过,则lca(u, v)必为v所属集合的代表元。p==v的情况类似。

我的第一道LCA问题的Tarjan算法,题目只有唯一的一组查询,实现起来非常简洁。

注意题目给树的格式:给出n-1个数对<u, v>,u为v的父节点。因此可以当作有向图用邻接表存储,同时记录各个节点的入度,入度为0的点为树根。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <vector>
 4 using namespace std;
 5 const int MAX_N = 10005;
 6 
 7 int parent[MAX_N];
 8 
 9 void init(){
10     for(int i=0; i<MAX_N; i++){
11         parent[i] = i;
12     }
13 }
14 int find(int x){
15     if(parent[x] == x) return x;
16     return parent[x] = find(parent[x]);
17 }
18 void unite(int x, int y){
19     x = find(x);
20     y = find(y);
21     if(x == y) return ;
22     parent[y] = x;
23 }
24 bool same(int x, int y){
25     return find(x) == find(y);
26 }
27 
28 vector<int> G[MAX_N];
29 int u, v;
30 int T;
31 int n;
32 int vis[MAX_N];
33 int indeg[MAX_N];
34 
35 void dfs(int r){
36     //printf("%d\n", r);
37     for(int i=0; i<G[r].size(); i++){
38         if(!vis[G[r][i]]){
39             dfs(G[r][i]);
40             unite(r, G[r][i]);//孩子合并到父节点 
41         }
42     }
43     vis[r] = 1; //后序遍历
44     if(r == u && vis[v]){
45         printf("%d\n", find(v));
46         return ;
47     }else if(r == v && vis[u]){
48         printf("%d\n", find(u));
49         return ;
50     }
51 }
52 
53 void lca(){
54     memset(vis, 0, sizeof(vis));
55     init();
56     int r = 0;
57     for(int i=1; i<=n; i++){
58         if(indeg[i]==0){
59             //printf("root : %d\n", i); //入度为0的是树根 
60             dfs(i);
61         }
62     }     
63 }
64 
65 int main()
66 {
67     freopen("1330.txt", "r", stdin);
68     scanf("%d", &T);
69     while(T--){
70         scanf("%d", &n);
71         memset(indeg, 0, sizeof(indeg));
72         for(int i=0; i<MAX_N; i++) G[i].clear();
73         for(int i=0; i<n-1; i++){
74             scanf("%d%d", &u, &v);
75             G[u].push_back(v);//有向图 
76             indeg[v]++;
77         }
78         scanf("%d%d", &u, &v);
79         lca();
80     }
81     return 0;
82 }

 

目录
相关文章
|
5月前
|
算法 JavaScript 程序员
程序员必知:《程序设计与算法(二)算法基础》《第一周枚举》熄灯问题POJ
程序员必知:《程序设计与算法(二)算法基础》《第一周枚举》熄灯问题POJ
30 0
|
6月前
|
算法 vr&ar Windows
Tarjan算法求LCA(最近公共祖先)
Tarjan算法求LCA(最近公共祖先)
40 0
|
安全 算法 Go
有向图的强联通分量(SCC)Tarjan算法
有向图的强联通分量(SCC)Tarjan算法
184 0
[算法刷题题解笔记] POJ 1106 Transmitters [计算几何|叉积|点线关系]
[算法刷题题解笔记] POJ 1106 Transmitters [计算几何|叉积|点线关系]
|
算法
图论——强连通分量:Tarjan算法。
在有向图G中,如果两个定点u,v间存在一条u到v的路径,也存在一条v到u的路径,则称u,v是强连通的。 若有向图G的任意两点都强联通,则称G是一个强联通图。 非强连通图的极大强连通子图称为强连通分量。   这里,极大强连通子图可以理解为一个子图是强连通图,且它的任意子图都不是强联通。
2632 0
|
算法 C++ BI
图论——强连通分量:Tarjan算法——练习1
上一次我们详细介绍了强连通分量的Tarjan算法,今天呢,我们来做一些习题来巩固Tarjan算法,毕竟它十分重要。 Tarjan算法详解 上面是上一次的详解,在做题时可供参考。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~                               练习一般采用洛谷题库。
1304 0
|
算法
算法学习之路|POJ - 2479最大子串和(简单dp)
给一个数字串,求这个数字串中两个不相交的子串和的最大值。
1295 0
|
算法
算法学习之路|POJ 1068 Parencodings(简单模拟)
有一个括号串(括号成对),给出一串数字数组p,p[i]表示从左往右第i个右括号左边共有p[i]个左括号,求一个数组w,w[i]表示第i个右括号和其所匹配的左括号之间有多少个左括号(包括这个左括号本身)
1079 0
|
存储 算法 数据建模