问题描述
|
目标:
我正在寻找一种算法,以找到图的最佳公共祖先,其中图中的节点可以具有零个,一个或两个父代。我不确定“最佳共同祖先”的术语:更好的术语可能是“最低共同祖先”或“最近共同祖先”等。如果有更好的术语,请提供URL“可以这样描述。
该算法可以访问完整的图形数据结构。
给定节点可能有零个,一个或两个父节点。这很关键,因为我在网络上看到的算法假定给定节点具有零个或一个父级,但没有两个父级(请参阅下面的参考资料)。例如,下图中的m1节点具有零个父级,因为它是根(可以有多个图的根)。 d3有两个父母,一个是d2,另一个是b2。
节点引用两个父节点(如果存在),并且引用所有子节点(如果它们存在),因此在树上和树下遍历是公平的。节点可以有零个或多个子节点。更改数据结构不是一种选择。
距离两个输入节点较近的节点比距离较远(即,靠近图的根)的节点更可取。
例如,下面给出的图表显示了一个可能的图表。在这种情况下,算法的输入将是节点b5和d4。节点b5和d4的最佳公共祖先是b2。 c2不是因为b3在通向b5的世系中。
该算法的可能答案最多为一个节点,而在两个输入节点没有共同祖先的情况下,空集是有效答案。
参考资料
Tarjan的离线最小共同祖先算法似乎暗示了零个或一个父代,因此,如果这是解决方案,则答案应包括对在该算法中如何计算两个父代的描述。最低共同祖先的维基百科页面似乎也只考虑了其节点具有零个或一个父级而不是两个父级的数据结构:
在树形数据结构中,每个
节点指向其父节点,...
图解:
解决方法
我经营一个家谱网站,并已使用以下算法解决了此问题。
对于两个节点,使用递归生成一个将节点名称与生成链接在一起的数组。以您的示例为例,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;