题目来源:最近公共祖先·一
题目描述
小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。
样例输入
11 JiaYan JiaDaihua JiaDaihua JiaFu JiaDaihua JiaJing JiaJing JiaZhen JiaZhen JiaRong JiaYuan JiaDaishan JiaDaishan JiaShe JiaDaishan JiaZheng JiaShe JiaLian JiaZheng JiaZhu JiaZheng JiaBaoyu 3 JiaBaoyu JiaLian JiaBaoyu JiaZheng JiaBaoyu LinDaiyu
样例输出
JiaDaishan JiaZheng -1
解题思路:首先定义一个Node类,其中name表示节点的名字,isVisited表示该节点是否被访问过,parentIndex表示其父节点在数组中的下标,每当接受一组输入数据(parent,child)时,就在数组中查找该parent节点和child节点是否创建,然后再建立关系,最后整个数组中的数据全部建立了关系。当接收到一对询问(first,second)时,首先将first以及first的祖先节点isVisited设置为true,second也是一样,如果发现当前节点的isVisited已经为true,说明first已经访问过该节点,并且该节点为(first,second)的最近公共子节点。为了加速查找,采用hashmap来记录节点信息。
具体算法(java版,可以直接AC)
1 import java.util.HashMap; 2 import java.util.Scanner; 3 4 public class Main { 5 6 private HashMapnodeMap; 7 private Node[]nodes; 8 private int index; 9 private int ancestorIndex; 10 11 public Main(){ 12 this.nodeMap=new HashMap (); 13 this.nodes=new Node[1001]; 14 this.index=0; 15 this.ancestorIndex=-1; 16 } 17 18 private void reset(){ 19 for(int i=0;i<this.index;i++){ 20 this.nodes[i].isVisited=false; 21 } 22 this.ancestorIndex=-1; 23 } 24 25 private int getNode(String nodeName){ 26 if(!this.nodeMap.containsKey(nodeName)){ 27 this.nodes[this.index]=new Node(nodeName); 28 this.nodeMap.put(nodeName, this.index); 29 this.index++; 30 } 31 return this.nodeMap.get(nodeName); 32 } 33 34 private void visit(int nodeIndex){ 35 if(nodeIndex>=0&&nodeIndex<this.index){ 36 if(this.nodes[nodeIndex].isVisited){ 37 this.ancestorIndex= nodeIndex; 38 return; 39 }else{ 40 this.nodes[nodeIndex].isVisited=true; 41 int parentIndex=this.nodes[nodeIndex].parentIndex; 42 this.visit(parentIndex); 43 } 44 } 45 } 46 47 public void addNode(String parent,String child){ 48 int parentIndex=this.getNode(parent); 49 int childIndex=this.getNode(child); 50 if(parentIndex>=0&&parentIndex<this.index 51 &&childIndex>=0&&childIndex<this.index){ 52 this.nodes[childIndex].parentIndex=parentIndex; 53 } 54 } 55 56 public void getAncestor(String first,String second){ 57 int firstIndex=this.getNode(first); 58 int secondIndex=this.getNode(second); 59 this.visit(firstIndex); 60 this.visit(secondIndex); 61 if(this.ancestorIndex>=0&&this.ancestorIndex<this.index){ 62 this.nodes[this.ancestorIndex].print(); 63 }else{ 64 System.out.println("-1"); 65 } 66 this.reset(); 67 } 68 69 public static void main(String[] args) { 70 71 Scanner scanner=new Scanner(System.in); 72 Main ancestor=new Main(); 73 int n=scanner.nextInt(); 74 for(int i=0;i ){ 75 String first=scanner.next(); 76 String second=scanner.next(); 77 ancestor.addNode(first, second); 78 } 79 int m=scanner.nextInt(); 80 for(int i=0;i ){ 81 String first=scanner.next(); 82 String second=scanner.next(); 83 ancestor.getAncestor(first, second); 84 } 85 } 86 87 } 88 89 class Node{ 90 public String name; 91 public int parentIndex; 92 public boolean isVisited; 93 public Node(String name){ 94 this.name=name; 95 this.parentIndex=-1; 96 this.isVisited=false; 97 } 98 public void print(){ 99 System.out.println(this.name); 100 } 101 }
算法效率不是很好,如果有好的算法可以留言,谢谢!