POJ 1330 Nearest Common Ancestors LCA题解
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 19728 | Accepted: 10460 |
Description

In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the root of the tree. Node x is an ancestor of node y if node x is in the path between the root and node y. For example, node 4 is an ancestor of node 16. Node 10 is also an ancestor
of node 16. As a matter of fact, nodes 8, 4, 10, and 16 are the ancestors of node 16. Remember that a node is an ancestor of itself. Nodes 8, 4, 6, and 7 are the ancestors of node 7. A node x is called a common ancestor of two different nodes y and z if node
x is an ancestor of node y and an ancestor of node z. Thus, nodes 8 and 4 are the common ancestors of nodes 16 and 7. A node x is called the nearest common ancestor of nodes y and z if x is a common ancestor of y and z and nearest to y and z among their common
ancestors. Hence, the nearest common ancestor of nodes 16 and 7 is node 4. Node 4 is nearer to nodes 16 and 7 than node 8 is.
For other examples, the nearest common ancestor of nodes 2 and 3 is node 10, the nearest common ancestor of nodes 6 and 13 is node 8, and the nearest common ancestor of nodes 4 and 12 is node 4. In the last example, if y is an ancestor of z, then the nearest
common ancestor of y and z is y.
Write a program that finds the nearest common ancestor of two distinct nodes in a tree.
Input
N. Each of the next N -1 lines contains a pair of integers that represent an edge --the first integer is the parent node of the second integer. Note that a tree with N nodes has exactly N - 1 edges. The last line of each test case contains two distinct integers
whose nearest common ancestor is to be computed.
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
Source
本题是一个多叉树,然后求两点的近期公共单亲节点。
就是典型的LCA问题。这是一个非常多解法的,并且被研究的非常透彻的问题。
原始的解法:从根节点往下搜索,若果搜索到两个节点分别在一个节点的两边。那么这个点就是近期公共单亲节点了。
Trajan离线算法:首次找到两个节点的时候,假设记录了他们的最低单亲节点,那么答案就是这个最低的单亲节点了。
问题是怎样有效记录这个最低单亲节点,并有效依据遍历的情况更新,这就是利用Union Find(并查集)记录已经找到的节点,并及时更新最新訪问的节点的当前最低单亲节点。
就是并查集的灵活运用啦,假设学会了并查集那么学这个算法是不难的了。
2015-1-24 update:
以下括号的分析好像有点问题:
(以下是简单思路差点儿相同是暴力法的解法,只是事实上相对本题来说就是一次查询,故此这个也是不错的方法,并且平均时间效率只是O(lgn),应该是非常快的了。
只是有思想和这个差点儿相同的。可是更加省内存的方法,就是从须要查找的节点往单亲节点查找,那么速度是一样的,只是省内存,由于仅仅须要记录一个父母节点就能够了。并且程序会简洁点。)
这种方法的基本思想是:
如果要查找u,v的LCA,
递归深度遍历整棵树,这个时候有三种情况:
1. 假设没哟找到u或者v当中一个节点。那么就返回0;
2 假设找到了u或v的当中一个节点。那么就返回找到的节点
3 假设找到u且找到v两个节点。那么就返回其父母节点。而这个父母节点正好是LCA,为什么呢?由于这个是逐层递归上去的算法,仅仅有在u和v的分叉节点能找到两个非零返回值,其它情况都仅仅能找到一个或者0个非零返回值。巧妙地利用了递归的特点。把LCA作为了终于的返回值。
由于最坏情况须要递归整棵树。故此这个算法的时间效率事实上是O(n),n为整棵树的节点数。
故此本算法尽管AC了,可是事实上时间效率还是蛮低的。
之前分析说是O(lgn)是不正确的。不好意思。假设误导了某些读者,那么表示抱歉。
还好以下算法是没错的。
本算法对递归的理解还是要求挺高的,对于刚開始学习的人还是有点难度。
- int const MAX_N = 10001;
- struct Node
- {
- bool notRoot;
- vector<int> children;
- };
- Node Tree[MAX_N];
- int N;
- int find(int r, int lNode, int rNode)
- {
- if (!r) return 0;
- if (r == lNode) return r;
- if (r == rNode) return r;
- vector<int> found;
- for (int i = 0; i < (int)Tree[r].children.size(); i++)
- {
- found.push_back(find(Tree[r].children[i], lNode, rNode));
- }
- int u = 0, v = 0;
- for (int i = 0; i < (int)found.size(); i++)
- {
- if (found[i] != 0)
- {
- if (u) v = found[i];
- else u = found[i];
- }
- }
- if (v) return r;
- return u;
- }
- void solve()
- {
- scanf("%d", &N);
- memset(Tree, 0, sizeof(Tree));
- int u, v;
- for (int i = 1; i < N; i++)
- {
- scanf("%d %d", &u, &v);
- Tree[u].children.push_back(v);
- Tree[v].notRoot = 1;
- }
- int root = 0;
- for (int i = 1; i <= N; i++)
- {
- if (!Tree[i].notRoot)
- {
- root = i;
- break;
- }
- }
- scanf("%d %d", &u, &v);
- int r = find(root, u, v);
- printf("%d\n", r);//if (lin && rin) 必定是存在点。故此无需推断
- }
- int main()
- {
- int T;
- scanf("%d", &T);
- while (T--)
- {
- solve();
- }
- return 0;
- }
以下是Tarjan离线算法,效率应该和上面是一样的。多次查询的时候就能提高效率。只是实际执行比上面快。
- #include <stdio.h>
- #include <string.h>
- #include <vector>
- using std::vector;
- int const MAX_N = 10001;
- struct Node
- {
- bool notRoot;
- bool vis;
- vector<int> children;
- };
- Node Tree[MAX_N];
- int N;
- int u, v;
- int parent[MAX_N];
- inline int find(int x)
- {
- if (!parent[x]) return x;
- return parent[x] = find(parent[x]);
- }
- inline void unionTwo(int p, int x)
- {
- p = find(p);
- x = find(x);
- if (p == x) return ;
- parent[x] = p;
- }
- bool LCATarjan(int root)
- {
- Tree[root].vis = true;
- if (root == u && Tree[v].vis == true)
- {
- printf("%d\n", find(v));
- return true;
- }
- if (root == v && Tree[u].vis == true)
- {
- printf("%d\n", find(u));
- return true;
- }
- for (int i = 0; i < (int)Tree[root].children.size(); i++)
- {
- if (LCATarjan(Tree[root].children[i])) return true;
- unionTwo(root, Tree[root].children[i]);
- }
- return false;
- }
- void solve()
- {
- scanf("%d", &N);
- memset(Tree, 0, sizeof(Tree));
- memset(parent, 0, sizeof(parent));
- for (int i = 1; i < N; i++)
- {
- scanf("%d %d", &u, &v);
- Tree[u].children.push_back(v);
- Tree[v].notRoot = 1;
- }
- int root = 0;
- for (int i = 1; i <= N; i++)
- {
- if (!Tree[i].notRoot)
- {
- root = i;
- break;
- }
- }
- scanf("%d %d", &u, &v);
- LCATarjan(root);
- }
- int main()
- {
- int T;
- scanf("%d", &T);
- while (T--)
- {
- solve();
- }
- return 0;
- }
POJ 1330 Nearest Common Ancestors LCA题解的更多相关文章
- POJ.1330 Nearest Common Ancestors (LCA 倍增)
POJ.1330 Nearest Common Ancestors (LCA 倍增) 题意分析 给出一棵树,树上有n个点(n-1)条边,n-1个父子的边的关系a-b.接下来给出xy,求出xy的lca节 ...
- poj 1330 Nearest Common Ancestors lca 在线rmq
Nearest Common Ancestors Description A rooted tree is a well-known data structure in computer scienc ...
- poj 1330 Nearest Common Ancestors LCA
题目链接:http://poj.org/problem?id=1330 A rooted tree is a well-known data structure in computer science ...
- POJ 1330 Nearest Common Ancestors (LCA,倍增算法,在线算法)
/* *********************************************** Author :kuangbin Created Time :2013-9-5 9:45:17 F ...
- POJ 1330 Nearest Common Ancestors(LCA模板)
给定一棵树求任意两个节点的公共祖先 tarjan离线求LCA思想是,先把所有的查询保存起来,然后dfs一遍树的时候在判断.如果当前节点是要求的两个节点当中的一个,那么再判断另外一个是否已经访问过,如果 ...
- POJ - 1330 Nearest Common Ancestors(基础LCA)
POJ - 1330 Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000KB 64bit IO Format: %l ...
- POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)
POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...
- POJ 1330 Nearest Common Ancestors(lca)
POJ 1330 Nearest Common Ancestors A rooted tree is a well-known data structure in computer science a ...
- POJ 1330 Nearest Common Ancestors 倍增算法的LCA
POJ 1330 Nearest Common Ancestors 题意:最近公共祖先的裸题 思路:LCA和ST我们已经很熟悉了,但是这里的f[i][j]却有相似却又不同的含义.f[i][j]表示i节 ...
随机推荐
- 如何上传base64编码图片到七牛云
接口说明 POST /putb64/<Fsize>/key/<EncodedKey>/mimeType/<EncodedMimeType>/crc32/<Cr ...
- HTML5API___Web Storage
Web Storage 是html5的本地存储规范 支持:移动平台基本支持 (opera mini除外) ie8+ff chrome 等 支持 它包含2个: sessionStorage 会话存储 ...
- OpenCV 开发环境环境搭建(win10+vs2015+opencv 3.0)
OpenCV 3.0 for windows(下载地址:http://opencv.org/): 本测试中,OpenCV安装目录:D:\Program Files\opencv,笔者操作系统为64位. ...
- spring 加载配置文件的相关配置总结
PropertyPlaceholderConfigurer 注意: Spring容器仅允许最多定义一个PropertyPlaceholderConfigurer(或<context:p ...
- 【转】CxImage图像库的使用
CxImage下载地址:http://www.codeproject.com/KB/graphics/cximage/cximage600_full.zip 作者:Davide Pizzolato C ...
- 浮点数(double)的优势
用 double 处理大数据 , 即使字符串位数超百位,同样可以用 sscanf 或 atof 来处理,却不会变成负数,原因是浮点数可以用指数表示,但精度会丢失,下面介绍利用这个性质解决的一些问题: ...
- 简单的mvvm light 应用
public class MainStudentModel:ViewModelBase { //实体 private StudentModel stu = new Stude ...
- JS字符串方法总结整理
//javascript字符串方法总结 1.String.charAt(n) //取得字符串中的第n个字符 2.String.charCodeAt(n) //取得字符串中第n个字符 ...
- A Byte of Python 笔记(8)
第10章 解决问题——编写一个 python 脚本 程序功能:为所有重要文件创建备份 设计: 1.需要备份的文件和目录由一个列表指定 2.备份应该保存在主备份目录中 3.文件备份称一个 zip 文件 ...
- KVO 的使用和举例
KVO(key-value Observer),通过命名可以联想到,一个监视着监视着键值配对,让一个对象A来监视另一个对象B中的键值,一旦B中的受监视键所对应的值发生了变化,对象A会进入一个回调函数, ...