目标:
我正在寻找一种算法来找到图的最佳共同祖先,其中图中的节点可以有零个,一个或两个父节点。我不确定“最佳共同祖先”的术语:更好的术语可能是“最低共同祖先”,或“最近的共同祖先”等。如果有更好的术语,请提供描述此类的URL。
该算法可以访问完整的图形数据结构。
给定节点可能有零个,一个或两个父节点。这是关键,因为我在网上看到的算法假定给定节点有零个或一个父节点,而不是两个父节点(参见下面的参考资料)。例如,下图中的m1节点具有零父项,因为它是根(可以有多个图的根)。 d3有两个父母,一个是d2,另一个是b2。
如果父节点存在,则节点可以引用父节点,并且如果它们存在则引用所有子节点,因此遍历树并在树下面是公平游戏。节点可以有零个或多个子节点。不能改变数据结构。
更靠近两个输入节点的节点比距离更远的节点更好(即更接近图的根)。
例如,下图给出了一个可能的图表。在这种情况下,算法的输入将是节点b5和d4。节点b5和d4的最佳共同祖先是b2。 c2不会是因为b3在通向b5的血统中。
算法的可能答案最多只能是一个节点,如果两个输入节点没有共同的祖先,则空集是有效答案。
参考资料
Tarjan's off-line least common ancestors algorithm似乎意味着零或一个父母,所以如果这是解决方案,那么答案应该包括对该算法中如何计算两个父母的描述。 Lowest common ancestor的维基百科页面似乎也只考虑其节点有零个或一个父节点的数据结构,而不是两个:
在树数据结构中每个 节点指向其父节点......
图:
答案 0 :(得分:1)
我运行了一个家谱网站,我之前使用以下算法解决了这个问题。
对于两个节点,使用递归生成一个数组,该数组将节点名称与生成链接起来。使用你的例子,b4比b5高1代; b3是2代;等:
$b5Tree = array('b4'=>1, 'b3'=>2, 'c3'=>2, 'b2'=>3, 'c2'=>3, ...);
$d4Tree = array('d3'=>1, 'b2'=>2, 'd2'=>2, 'b1'=>3, 'd1'=>3, ...);
基本情况是检查第一个节点是否出现在第二个树中,反之亦然。如果它存在,那么你有答案。
否则,遍历其中一棵树,查找公共节点ID,并跟踪最小生成。
$minNodeID = null;
foreach ($b5Tree as $nID => $gen)
{
if (($d4Tree[$nID] != 0) and (($d4Tree[$nID] + $gen) < $minSummedGen))
{
$minSummedGen = $d4Tree[$nID] + $gen;
$minNodeID = $nID;
}
}
return $minNodeID;