フォレスト内のすべてのノードの高さを見つける


8

私にはフォレスト、つまり有向エッジがあり、サイクルがない(有向または無向)ノードがあります。頂点高さを、v入力エッジがない場合は0として定義するか、高さ0の頂点に到達するために逆方向に移動するエッジの最大数を定義します。 ここに画像の説明を入力してください

また、ノードの平均次数は小さな定数、たとえば2程度であることも知っています。すべての頂点の高さを見つけるには、2つのアルゴリズムを考えることができます。

歩行アルゴリズム

  1. 入力エッジのない頂点について、とマークしh=0ます。
  2. 各頂点について、出て行くエッジをたどり、以前の高さがより小さければ、遭遇した各頂点の高さを更新します。h=0

フロンティアアルゴリズム

  1. 通過マークのない着信エッジを持つ頂点の、およびフロンティアとしてこれらをマークします。h=0
  2. すべてのフロンティア頂点について、親がフロンティア以下に子を持っているかどうかを確認します。もしそうであれば、親に加え、その子の中で最大の高さがあることをマークします。親がフロンティアにいるとマークします。1
  3. フロンティアを超えるものがなくなるまで、2を繰り返します。

私の質問:

  1. この問題に名前はありますか、そして最もよく知られている最速の解決策はありますか?
  2. 私はすべての頂点から単に上に行くことが最も速い解決策であると考える傾向があります。私は正しいですか?h=0

回答:


7

まず第一に、どのアルゴリズムが最もよく機能するかを言うためにデータにどのようにアクセスできるかは少し異なります。

v

高さv={最高あなた の子 v高さあなた+1もし あなた 葉ではありません0さもないと

したがって、すべての根をスキャンし、征服者を分割することで高さを決定できます。すべての頂点に最大2回タッチします(ルートのスキャン+トラバース)。あなたが提案したアプローチでは、いくつかの頂点に何度も触れる必要があるかもしれません。

ところで、フォレストがあるため、頂点よりもエッジが少ないため、平均次数が2未満であることがわかります(したがって、線形時間でルートをテストできます)。


+1; 多くの場合、再帰的ソリューションは分析が簡単です。また、子ポインターが既にあるかどうか、ループベースのソリューションまたは再帰ベースのソリューションが必要かどうかにも依存します。
Joe

私は分析が好きです!これを反復形式に変換する方法を指摘する初心者を誰かが助けることもできますか?
highBandWidth

4

この問題に正式な名前があるかどうかはわかりません。あなたのタイトルはそれを十分に要約します。重複する作業を回避するように注意すれば、高さ0のノードから上に歩くのが速くなります。多くの子を持つノードがあり、このノードの上にルートまでの長いパスがあるとします。また、それぞれの子の高さが異なると仮定します。各子は、問題のノードの高さを更新できます。それで大丈夫です。ただし、すべての子が高さを報告するまで、そのノードの上の長いパスも更新しないでください。

結果のアルゴリズムは線形時間で実行され、疑似コードは次のようになります。

initialize a queue Q
initialize all nodes to have a property: maxChildHeight = 0
initialize all nodes of in-degree 0 to have height = 0
Add all nodes of in-degree 0 to Q
while Q is non-empty:
  pop a node v from the front of Q
  subtract 1 from the indegree of the parent of v
  set parent.maxChildHeight = max(height(v), parent.maxChildHeight)
  if the indegree of the parent is 0:
      parent.height =  maxChildHeight + 1
      add the parent to Q

3

非常によく似た問題となるのは、「ルート付き有向ツリーの並列プレフィックス」です。アルゴリズムは、各ノードからルートへのエッジの数を見つけます。したがって、ルートの値は0になりますが、たとえば右下のノードの値は2になります。

以下のアルゴリズムは重み付きエッジのより一般的な問題を解決しますが、すべてのiについてW(i)を1に初期化するだけでよいことに注意してください。そして、各ノードiの後続ノードはP(i)= jで与えられます。

for 1 ≤ i ≤ n do in parallel
    S(i) = P(i)
    while S(i) != S(S(i)) do
        W(i) = W(i) + W(S(i))
        S(i) = S(S(i))

以下の画像は、パスの長さの「半分」を示し、対数の実行時間を理解しやすくしています。ただし、計算されたノードの高さは表示されません。

ここに画像の説明を入力してください

(Joseph Jajaによる「Introduction to Parallel Algorithms」から)。

複数のプロセッサを使用すると、O(lg n)時間で解けるが、O(n lg n)演算を使用する。線形作業に落とすためのハックがありますが、少し複雑です。


ありがとう!何をS(i)表していますか?
highBandWidth

後続ノード。したがって、適切なツリーの反復1では、S(9)= 10、S(10)= 11、S(11)= 12、S(12)= 13およびW(9)= 1、W(10)= 1 、W(11)= 1、W(12)= 1。反復2では、S(9)= 11、S(10)= 12、S(11)= 13、S(12)= 13およびW(9)= 2、W(10)= 2、W(11) = 2、W(12)= 1。反復3では、S(9)= 13、S(10)= 13、S(11)= 13、S(12)= 13およびW(9)= 2 + 2、W(10)= 2 + 1、 W(11)= 2、W(12)= 1。
Unfun Cat

詳細を確認しようとすると、すべてのS(i)とW(i)が同時に更新されることを想像する必要があります。これはあいまいかもしれませんが、古典的な並列問題であり、あなたが説明したものに非常に近いため、投稿したかったのです。
Unfun Cat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.