次のような有向非循環グラフを想像してください。
2つの任意のノードの最小共通祖先(LCA)を決定するために使用できるアルゴリズムはどれですか。たとえば、次の共通祖先です。
注意:
Den Romanのリンク は有望に思えますが、少し複雑に思えたので、別の方法を試しました。これが私が使った簡単なアルゴリズムです:
xとyの2つのノードでLCA(x、y)を計算するとします。各ノードには値color
とcount
が必要です。 whiteおよびに初期化されます。
count
を1つ増やしますcount
値がに設定されている各redノードがソリューションです。
グラフによっては、複数のソリューションが存在する場合があります。たとえば、次のグラフについて考えてみます。
LCA(4,5)の可能な解は1と2です。
3つ以上のノードのLCAが必要な場合でも機能します。ノードごとに異なる色を追加する必要があるだけです。
同じ問題の解決策を探していたところ、次の論文で解決策を見つけました。
http://dx.doi.org/10.1016/j.ipl.2010.02.014
つまり、最も低い共通の祖先を探すのではなく、このホワイトペーパーで定義する最も低いSINGLEの共通の祖先を探します。
私はそれが古い質問でかなり良い議論であることを知っていますが、解決するいくつかの同様の問題があったので、 JGraphT の Lowest Common Ancestor アルゴリズムに出くわしたので、これは助けて:
グラフでxとyの祖先を検索するとします。
ベクトルの配列を維持する-parents(各ノードの親を格納する)。
最初にbfs(各頂点の親を保存し続ける)を実行し、xのすべての祖先を見つけ(xの親を見つけてparentsを使用し、xのすべての祖先を見つけます)、それらをベクトルに保存します。また、各親の深度をベクターに格納します。
同じ方法を使用してyの祖先を見つけ、それらを別のベクトルに格納します。これで、xとyの祖先をそれぞれ深度とともに格納する2つのベクトルがあります。
LCAは共通の祖先であり、最大の深さがあります。深さは、ルート(in_degree = 0の頂点)からの最長距離として定義されます。これで、ベクトルを深さの降順でソートして、LCAを見つけることができます。この方法を使用すると、複数のLCA(存在する場合)を見つけることもできます。
ちょうどいくつかの野生の考え。両方の入力ノードをルートとして使用し、2つのBFSを段階的に同時に実行するのはどうでしょうか。特定のステップで、BLACKセットに重複がある場合(訪問済みノードの記録)、アルゴリズムが停止し、重複するノードがLCAになります。このように、他の一般的な祖先は、私たちが発見したものよりも距離が長くなります。
グラフにサイクルがある場合、「祖先」は大まかに定義されます。おそらく、DFSまたはBFSのツリー出力の祖先ですか?あるいは、「祖先」とは、E
とB
からのホップ数を最小化するダイグラフのノードを意味しますか?
複雑さについて心配していなければ、すべてのノードからE
とB
の両方へのA *(またはダイクストラの最短パス)を計算できます。 E
とB
の両方に到達できるノードの場合、PathLengthToE + PathLengthToB
を最小化するノードを見つけることができます。
編集:あなたはいくつかのことを明確にしたので、私はあなたが探しているものを理解していると思います。
ツリーを「上に」上ることしかできない場合は、E
からBFSを実行し、B
からBFSを実行することをお勧めします。グラフ内のすべてのノードには、2つの変数が関連付けられています:B
からのホップとE
からのホップ。 B
とE
の両方にグラフノードのリストのコピーを持たせます。 B
のリストはB
からのホップでソートされ、E
のリストはE
からのホップでソートされます。
B
のリスト内の各要素について、E
のリスト内で検索してみてください。 B
からのホップ+ E
からのホップでソートされた3番目のリストに一致を配置します。 B
のリストを使い果たした後、3番目にソートされたリストの先頭にLCAが含まれているはずです。これにより、1つのソリューション、複数のソリューション(B
のBFS順序によって任意に選択)、またはソリューションなしが可能になります。
http://www.gghh.name/dibtp/2014/02/25/how-does-Mercurial-select-the-greatest-common-ancestor.html
このリンクはそれがMercurialでどのように行われるかを説明します-基本的な考え方は、指定されたノードのすべての親を見つけ、ルートからの距離ごとにそれらをグループ化し、それらのグループで検索を行うことです。
DAG(有向非巡回グラフ)でLCAを見つけるには、まったく同じものが必要です。 LCA問題はRMQ(範囲最小クエリ問題)に関連しています。
LCAをRMQに削減し、有向非循環グラフから任意の2つのノードの必要なLCAを見つけることができます。
私は このチュートリアル 詳細と良いとわかりました。私もこれを実装する予定です。
私はO(| V | + | E |)時間複雑性ソリューションを提案しています。このアプローチは正しいと思います。それ以外の場合は修正してください。
有向非循環グラフを考えると、2つの頂点vとwのLCAを見つける必要があります。
ステップ1:bfs http://en.wikipedia.org/wiki/Breadth-first_search を使用し、時間の複雑さO(| V | + | E |)を使用して、ルート頂点からすべての頂点の最短距離を見つけます。各頂点の親を見つけます。
ステップ2:ルート頂点に到達するまで、親を使用して両方の頂点の共通の祖先を検索します。時間の複雑さ-2 | v |
ステップ3:LCAは、最大の最短距離を持つ共通の祖先になります。
したがって、これはO(| V | + | E |)時間複雑度アルゴリズムです。
私が間違っている場合、または他の提案が歓迎されている場合は、私を修正してください。