题目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. 看懂物联网fr

        看懂物联网 2015-10-11 物联网世界 1.第三次IT浪潮 互联网时代的特征是信息驱动了生产力,无论众包.订单式生产这些理论:还是B2C.O2O各类业务模式:归根结底,是信息优化了生产关 ...

  2. Java命令行实用工具jps和jstat 专题

    在Linux或其他UNIX和类UNIX环境下,ps命令想必大家都不陌生,我相信也有不少同学写过 ps aux | grep java | grep -v grep | awk '{print $2}' ...

  3. MVC View与Controller分离

    新建了一个 Separate 解决方案, 如下图 Separate.UI    UI层. 引用 Separate.Home Separate.Home 把Home控制器分享到 一个类库中 并引用(Sy ...

  4. 部署WebService服务碰到的一个小问题

    在部署WebService服务到IIS上之后,发现一直无法在浏览器访问到编写的asmx文件,一直提示404或403错误.提示当前访问的文件时脚本文件. 1.首先检查了在IIS上部署WebService ...

  5. Jquery each跳出循环

    Jquery each跳出循环break--return false--跳出所有循环continue--return true--跳出当前循环

  6. 1008 选数 2002年NOIP全国联赛普及组

    1008 选数 2002年NOIP全国联赛普及组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Description ...

  7. selenium3+webdriver学习笔记1(访问常用请求)

    #!/usr/bin/env python# -*- coding:utf-8 -*- from selenium import webdriverimport osimport time url1= ...

  8. Autoit3脚本编写举例

    以任务管理器为例 1.首先打开任务管理器 2.点击结束任务操作 第一步打开任务管理器 run("C:\WINDOWS\system32\taskmgr.exe"); 第二步点击结束 ...

  9. 使用ABAP代码提交SAP CRM Survey调查问卷

    Jerry之前曾经写过两篇关于SAP CRM Survey调查问卷的技术文章: SAP CRM Survey调查问卷的模型设计原理解析 如何使用SAP CRM Marketing Survey创建一个 ...

  10. Happy Equation

    Source: The 10th Shandong Provincial Collegiate Programming Contest 题解: 因为2^p为偶数,所以a,x的奇偶性相同 1.当a为奇数 ...