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 的 ...
随机推荐
- Vue双向绑定简单实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 第二十章 排查和调试Web程序 之 设计异常处理策略
1. 概述 本章内容包括: 多层架构中的异常处理.使用global.asax 或 自定义的HttpHandler 或 web.config中的属性来显示特定的错误页.处理 first chance 异 ...
- Java技术面试汇总
1.servlet执行流程 客户端发出http请求,web服务器将请求转发到servlet容器,servlet容器解析url并根据web.xml找到相对应的servlet,并将request.resp ...
- JS将人民币小写金额转换为大写
/** 数字金额大写转换(可以处理整数,小数,负数) */ function smalltoBIG(n) { var fraction = ['角', '分']; var digit = ['零', ...
- epoll使用总结
epoll的使用总结 使用epoll来实现一个tcp server,中间碰到了不少使用细节上的问题,总结一下. man epoll里推荐的使用方法 epoll使用代码 #define MAX_EVEN ...
- 科学效法自然:微软研究人员测试AI控制的滑翔机
编者按:正如一颗苹果砸出了万有引力,自然界所有存在的事物和现象都有其科学合理的一面,小小的鸟儿也能够给科学带来丰富的灵感和启示. 最近,微软研究人员从自然出发,研究鸟类能够自由停留在空中的科学原理,并 ...
- 掌握 Azure 的注册、帐户和订阅管理 Azure 上云须知
计划使用由世纪互联运营的 Microsoft Azure 的用户,可通过下列流程注册开通并购买所需 Azure 服务:信息获取 > 试用 > 购买 > 账户/订阅管理 > 支付 ...
- HDU 5500 Reorder the Books (水题)
题意: 有n本书,编号为1~n,现在书的顺序乱了,要求恢复成有序的样子,每次只能抽出其中一本并插到最前面,问最少需要多少抽几次? 思路: 如果pos[i]放的不是书i的话,则书i的右边所有的书都必须抽 ...
- 51nod 1572 宝岛地图
题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 勇敢的水手们到达了一个小岛,在这个小岛上,曾经有海盗在这里埋下了一些宝藏.然而,我 ...
- noip模拟赛#45
T1:n<=1e6,求最小的区间包含(1,m)的所有数. =>双指针扫一遍即可 #include<cstdio> #include<cstring> #includ ...