题目1 : 最近公共祖先·一

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

小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一下 第十三周]的更多相关文章

  1. hiho #1062 : 最近公共祖先·一(树,最近祖先)

    #1062 : 最近公共祖先·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Ho最近发现了一个神奇的网站!虽然还不够像58同城那样神奇,但这个网站仍然让小Ho乐在 ...

  2. lintcode :最近公共祖先

    题目 最近公共祖先 给定一棵二叉树,找到两个节点的最近公共父节点(LCA). 最近公共祖先是两个节点的公共的祖先节点且具有最大深度. 样例 对于下面这棵二叉树 4 / \ 3 7 / \ 5 6 LC ...

  3. 二叉树最近公共祖先(LeetCode)

    给定一个二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p.q,最近公共祖先表示为一个结点 x,满足 x 是 p.q 的祖先且 x 的深 ...

  4. [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 ...

  5. [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 ...

  6. [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 ...

  7. 利用Tarjan算法解决(LCA)二叉搜索树的最近公共祖先问题——数据结构

    相关知识:(来自百度百科)  LCA(Least Common Ancestors) 即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. 例如: 1和7的最近公共祖先为5: 1和5的 ...

  8. jzoj4313 电话线铺设(最小生成树+最近公共祖先)

    题面 \(solution:\) 这道题很奇妙,需要对kruskal重构树有足够的了解!我们先对王牌电缆实行kruskal重构树,然后我们再来枚举每一条李牌电缆,我们将某一条李牌电缆加进这棵树中必然构 ...

  9. LeetCode--235--二叉树的最近公共祖先

    问题描述: 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p.q,最近公共祖先表示为一个结点 x,满足 x 是 p.q 的 ...

随机推荐

  1. (转)linux dumpe2fs命令

    linux dumpe2fs命令 命令名称 dumpe2fs - 显示ext2/ext3/ext4文件系统信息. dumpe2fs命令语法 dumpe2fs [ -bfhixV ] [ -o supe ...

  2. (转)io优化

    原文:http://blog.csdn.net/gzh0222/article/details/9227393 1.系统学习 IO性能对于一个系统的影响是至关重要的.一个系统经过多项优化以后,瓶颈往往 ...

  3. [FACT_采购信息]增加了延期天数

    [延期天数]是指的采购单上的货品交货日期 减 [厂家来货]单据货品第一次到货日期. [FACT_采购信息] SELECT p.[Purchase_ID] [采购单号ID], p.[Supply_No] ...

  4. SSH 的端口转发

    第一部分 概述 当你在咖啡馆享受免费 WiFi 的时候,有没有想到可能有人正在窃取你的密码及隐私信息?当你发现实验室的防火墙阻止了你的网络应用端口,是不是有苦难言?来看看 SSH 的端口转发功能能给我 ...

  5. Java常用函数式接口--Consumer接口andThen()方法使用案例(二)

    Java常用函数式接口--Consumer接口使用案例

  6. asp.net mvc整合Nhibernate的配置方法

    http://blog.csdn.net/xz2001/article/details/8452794 http://www.cnblogs.com/GoodHelper/archive/2011/0 ...

  7. Linux系统日志分析

    Linux系统拥有非常灵活和强大的日志功能,可以保存几乎所有的操作记录,并可以从中检索出我们需要的信息. 大部分Linux发行版默认的日志守护进程为 syslog,位于 /etc/syslog 或 / ...

  8. SharePoint 2010 缺少站点保存为模板选项

    如果您尝试在SharePoint Server 2010中保存网站,并且没有看到"将网站另存为模板"选项,则可能是因为该网站已启用发布功能.如果使用站点发布功能,则有几个选项可将网 ...

  9. 修改wamp的数据库密码

    方法/步骤     一:修改数据库密码 1.点开MySQL console进入数据库编辑框,然后按回车键,会出现图2的效果. 2.接着输入“use mysql” 下面提示“Database chang ...

  10. [web笔记]解决跨域问题以及axios每次提交session变化的问题