Solution: 最近公共祖先·一 [hiho一下 第十三周]
题目1 : 最近公共祖先·一
描述
小Ho最近发现了一个神奇的网站!虽然还不够像58同城那样神奇,但这个网站仍然让小Ho乐在其中,但这是为什么呢?
“为什么呢?”小Hi如是问道,在他的观察中小Ho已经沉迷这个网站一周之久了,甚至连他心爱的树玩具都弃置一边。
“嘿嘿,小Hi,你快过来看!”小Ho招呼道。
“你看,在这个对话框里输入我的名字,在另一个对话框里,输入你的名字,再点这个查询按钮,就可以查出来……什么!我们居然有同一个祖祖祖祖祖爷爷?”
“诶,真是诶……这个网站有点厉害啊。”小Hi不由感叹道。
“是啊,这是什么算法啊,这么厉害!”小Ho也附和道。
“别2,我说的是他能弄到这些数据很厉害,而人类的繁殖树这种层数比较浅的树对这类算法的要求可是简单的不得了,你都能写出来呢!”小Hi道。
“啊?我也能写出来?可是……该从哪开始呢?”小Ho困惑了。
小Ho要面临的问题是这样的,假设现在他知道了N个人的信息——他们的父亲是谁,他需要对于小Hi的每一次提问——两个人的名字,告诉小Hi这两个人的是否存在同一个祖先,如果存在,那么他们的所有共同祖先中辈分最低的一个是谁?
输入
每个测试点(输入文件)有且仅有一组测试数据。
每组测试数据的第1行为一个整数N,意义如前文所述。
每组测试数据的第2~N+1行,每行分别描述一对父子关系,其中第i+1行为两个由大小写字母组成的字符串Father_i, Son_i,分别表示父亲的名字和儿子的名字。
每组测试数据的第N+2行为一个整数M,表示小Hi总共询问的次数。
每组测试数据的第N+3~N+M+2行,每行分别描述一个询问,其中第N+i+2行为两个由大小写字母组成的字符串Name1_i, Name2_i,分别表示小Hi询问中的两个名字。
对于100%的数据,满足N<=10^2,M<=10^2, 且数据中所有涉及的人物中不存在两个名字相同的人(即姓名唯一的确定了一个人)。
输出
对于每组测试数据,对于每个小Hi的询问,输出一行,表示查询的结果:如果根据已知信息,可以判定询问中的两个人存在共同的祖先,则输出他们的所有共同祖先中辈分最低的一个人的名字,否则输出-1。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
一些看法:
这是一道非传统意义上的算法题,因为它没有考到任何成型的算法思想(如:动态规划、费用流、图论等),甚至连搜索不用.....
从这个层面上来讲,这是一道比较简单的题目。但解这道题并不需要任何的先验的算法知识,只要会写C/Java都能解。
因此,这题考察的是对问题的理解,隐含条件的捕捉,以及将思路转换为代码的能力。虽然不难,但还是很有新意的,是技术岗笔试很好的选题参考。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Solution:
这道题的关键是一个常识中的常识:虽然一个爸爸可能有很多儿子,但每个儿子都只可能有一个爸爸。
根据这一点,对于任意的点P,其祖先的个数为n<-[0,N)。
接下来,我们要找Pa与Pb的共同的祖先。最简单的思路,就是遍历 {Pa的祖先}*{Pb的祖先}的所有组合,O(N^2)的时间复杂度,单点1000ms应该能过,M(<=100)点10s能不能过未知。
Anyway,即使过了该题的数据,这个方法显然很呆萌.......anything but 机智~~
让我们更机智一点吧~
先整理一下思路~
对于一点P,我们可以求出他的祖先序列 Plist=[p(1)...p(i),p(i+1)...p(n)],其中p(i+1)是p(i)的唯一的父亲。
因此,在Plist中,任意一点p(i)->p(n)的序列是唯一的。
因此,如果Pa,Pb存在公共祖先,即存在i,j使得Pa_list(i)=Pb_list(j)的话,必定有Pa_list(i+1)=Pb_list(j+1),
进而有Pa_list(na)=Pb_list(na-i+j) 或者 Pa_list(na-j+i)=Pb_list(nb)。
简而言之,如果存在公共祖先,则两个祖先序列中的其中一个的老祖宗,必定也存在于另一个祖先序列中。因此,我们只需要O(2*N)即能确定是否存在祖先了。
之后,只要不断回溯序列,找到辈分最小的共同祖先即可。
回顾整个解题过程,不难发现,祖先序列的唯一性(单支性)是解题的关键。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面贴出AC代码以供参考,建议有兴趣的童鞋们自己写一遍(记得在每次输出后加上换行符哟^ ^):

#include <iostream>
#include <map>
#include <string>
#include <string.h>
using namespace std; int M,N;
map<string,string> mp;
string lst[][];
int len[]; int find_root(int j){
int i=;
while(mp.count(lst[j][i])>){
lst[j][i+]=mp[lst[j][i]];
i++;
}
return i;
} void sourcing(){
int a[];
for(int j=;j<;j++)
len[j]=find_root(j); bool b=false;
int la=len[],lb=len[];
while(la>=&&lb>=){
if(lst[][len[]]==lst[][lb]){
la=len[];
b=true;
break;
}
if(lst[][len[]]==lst[][la]){
lb=len[];
b=true;
break;
}
la--;lb--;
}
if(b){
while(la>=&&lb>=)
if(lst[][la]==lst[][lb]){
la--;lb--;
}else{
break;
}
la++;lb++;
cout<<lst[][la]<<"\n";
}else{
cout<<-<<"\n";
}
} int main(){
cin>>N;
string a,b;
for(int i=;i<N;i++){
cin>>a>>b;
mp[b]=a;
}
cin>>M;
for(int i=;i<M;i++){
cin>>lst[][]>>lst[][];
sourcing();
} return ;
}
Solution: 最近公共祖先·一 [hiho一下 第十三周]的更多相关文章
- hiho #1062 : 最近公共祖先·一(树,最近祖先)
#1062 : 最近公共祖先·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho最近发现了一个神奇的网站!虽然还不够像58同城那样神奇,但这个网站仍然让小Ho乐在 ...
- lintcode :最近公共祖先
题目 最近公共祖先 给定一棵二叉树,找到两个节点的最近公共父节点(LCA). 最近公共祖先是两个节点的公共的祖先节点且具有最大深度. 样例 对于下面这棵二叉树 4 / \ 3 7 / \ 5 6 LC ...
- 二叉树最近公共祖先(LeetCode)
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p.q,最近公共祖先表示为一个结点 x,满足 x 是 p.q 的祖先且 x 的深 ...
- [Swift]LeetCode235. 二叉搜索树的最近公共祖先 | Lowest Common Ancestor of a Binary Search Tree
Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BS ...
- [Swift]LeetCode236. 二叉树的最近公共祖先 | Lowest Common Ancestor of a Binary Tree
Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. According ...
- [leetcode]236. Lowest Common Ancestor of a Binary Tree二叉树最近公共祖先
Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. Accordi ...
- 利用Tarjan算法解决(LCA)二叉搜索树的最近公共祖先问题——数据结构
相关知识:(来自百度百科) LCA(Least Common Ancestors) 即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. 例如: 1和7的最近公共祖先为5: 1和5的 ...
- jzoj4313 电话线铺设(最小生成树+最近公共祖先)
题面 \(solution:\) 这道题很奇妙,需要对kruskal重构树有足够的了解!我们先对王牌电缆实行kruskal重构树,然后我们再来枚举每一条李牌电缆,我们将某一条李牌电缆加进这棵树中必然构 ...
- LeetCode--235--二叉树的最近公共祖先
问题描述: 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p.q,最近公共祖先表示为一个结点 x,满足 x 是 p.q 的 ...
随机推荐
- .net C#实现 中文转Unicode、Unicode转中文 及与js对应关系
中文转Unicode:HttpUtility.UrlEncodeUnicode(string str); 转换后中文格式:"%uxxxx" 举例:"柳_abc123&q ...
- 《java学习三》并发编程 -------线程池原理剖析
阻塞队列与非阻塞队 阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞,直到 ...
- Activemq和Rabbitmq端口冲突
端口5672被占用了!使用cmd命令行查到被erl.exe占用了,想到这不是RabbitMQ的服务嘛 netstat -aon | findstr "5672"tasklist | ...
- Lodop套打
记录一下Lodop套打模板 实现打印功能需电脑已经连接打印机(打印什么类型的东西就连接相应的打印机 (普通大打印机 打印标签 打印发票各种打印机))和已经安装好lodop控件 控件可到官网进行下载 h ...
- c# 基础字符串
ToLower():得到字符串的小写形式.注意字符串是不可变的,所以这些函数都不会直接改变字符串的内容,而是把修改后的字符串的值通过函数返回值的形式返回.s.ToLower()与s=s.ToLower ...
- 总结一下WindowListener的用法
记录一下便于自己查看 1.WindowListener java.awt.event 接口 WindowListener public interface WindowListener extends ...
- angularJS在移动端的点击事件延迟问题
在运用angular开发移动端的应用时,发现它并没有将ng-click做兼容,在移动端使用ng-click事件仍然会有300ms延迟.后来发现angular有一个专门针对移动端的模块:angular- ...
- ThreadLocal的内存泄露
ThreadLocal的目的就是为每一个使用ThreadLocal的线程都提供一个值,让该值和使用它的线程绑定,当然每一个线程都可以独立地改变它绑定的值.如果需要隔离多个线程之间的共享冲突,可以使用T ...
- iOS 学习随记 (一)
入行IT也已经很多年了,厌倦了Windows平台的工作, 4月初突然抽风买了台Mac就开始决定转身做iOS/OS X下的App开发了. 从适应Mac机器到开始编程没有花费太长时间,也因为有C#和Jav ...
- 有一个无效 SelectedValue,因为它不在项目列表中
“Drp_XX”有一个无效 SelectedValue,因为它不在项目列表中 出现以上异常的原因肯定是将DrowDownList控件的SelectedValue属性赋值为一个列表中不存在的值.那么我们 ...