web-dev-qa-db-ja.com

有向グラフと線形時間で、2つの頂点間の異なる最短経路の数を見つける方法は?

演習は次のとおりです。

Vとwを有向グラフG =(V、E)の2つの頂点とします。線形時間アルゴリズムを設計して、vとwの間の異なる最短パス(必ずしも頂点が互いに素ではない)の数を見つけます。注:Gのエッジは重み付けされていません


この消費税について、次のように要約します。

  1. 有向グラフです
  2. 異なる最短パスの数を要求します。最初に、パスは最短である必要があり、次に同じ長さの最短パスが複数ある場合があります。
  3. vとwの間であるため、vからwおよびwからvの両方をカウントする必要があります。
  4. 線形時間。
  5. グラフは重み付けされません。

上記の点から、私は次のことを考えています:

  1. Dijkstra’s Algorithm を使用する必要はありません。グラフに重みが付けられておらず、単一のパスだけでなく、すべての最短パスを見つけようとしているためです。
  2. 最短パスの数に対してcountを維持します
  3. 最初にvからBFSを使用し、global level情報も維持したい
  4. global levelを1つずつ増やすと、BFSが新しいレベルに達します
  5. また、wへの最短パスのshortest level情報を維持します
  6. 旅行中に初めて会ったとき、global levelshortest levelcount++に割り当てます。
  7. global levelshortest levelに等しい限り、wに再び会うたびにcountを増やします。
  8. global levelshortest levelより大きくなった場合、パスではなく最短パスを探しているため、旅行を終了します。
  9. その後、wからvに対して2-8を繰り返し

私のアルゴリズムは正しいですか? vをwに、次にwをvにすると、それはまだ線形時間と見なされますか?

24
Jackson Tale

これに関するいくつかのアイデアがあります。

  • 同じ頂点を介してxに複数のパスがある場合、または同じDFSレベルでxが複数回検出された場合、v-> wからノードxを経由する複数の最短パスのみが可能です。

証明:同じ頂点からxに入る複数のパスがある場合は、明らかにxを通る複数の方法があります。これは簡単です。ここで、xに入る各頂点を介してxに入る方法は1つしかないと仮定します(最大)。

Xが以前に検出された場合、現在のパスはいずれも別の最短パスに貢献できません。 xは以前に検出されているため、後に続くすべてのパスは、以前の最短パスより少なくとも1つ長くなります。したがって、これらのパスはいずれも合計に寄与できません。

ただし、これは各ノードに1回しか遭遇せずに終了することを意味します。したがって、通常のBFSは問題ありません。

  • レベルを知る必要はありません。代わりに、最終ノードに到達すると最終番号を取得できます。

これは非常に単純なアルゴリズムにコンパイルできます。これは主にBFSです。

 - Mark nodes as visited as usual with BFS.
 - Instead of adding just nodes to the queue in the DFS add nodes plus number of incoming paths.
 - If a node that has been visited should be added ignore it.
 - If you find a node again, which is currently in the queue, do not add it again, instead add the counts together.
 - Propagate the counts on the queue when adding new nodes.
 - when you encounter the final, the number that is stored with it, is the number of possible paths.
20
LiKao

あなたのアルゴリズムはグラフのように壊れます

  *   *   *   1
 / \ / \ / \ / \
v   *   *   *   w
 \ / \ / \ / \ /
  *   *   *   2

すべてのエッジが左から右に向けられています。 1を通るパスと2を通るパスの2つをカウントしますが、vから8つの異なる最短パスで12の両方に到達できます、合計16個。

9
qrqrq

Qrqrqが示すように、一部のグラフではアルゴリズムが失敗しますが、BFSのアイデアは優れています。代わりに、ゼロに初期化するサイズ|V|の配列zを維持します。 z[i]i未満の距離で、検出された頂点levelへの最短パスの数を保持します。 |V|dから頂点vまでの距離になるように、サイズd[i]の配列iも維持します。その距離がlevelより小さい場合。 levelを0に、d[v]を0に、z[v]を1に初期化し(vからvに長さ0の単一パスがあります)、dの他のすべてのエントリを-1に設定します。 zから0へ。

これで、BFSでiからjへのEdgeに遭遇するたびに、次のようになります。

  • d[j] = -1の場合、d[j] := levelおよびz[j] := z[i]を設定します。
  • d[j] = levelの場合、z[j] := z[j] + z[i]を設定します。
  • それ以外の場合は、何もしません。

理由は、vからiへの最短パスごとに、vからjへの最短パスが1つあるためです。これにより、vから各頂点への最短パスの数が線形時間で得られます。ここで、wから始めて同じことを繰り返します。

4
Erik P.

このアルゴリズムは私には正しいようです。

ご存知のように、BFSは線形時間(O(N))検索です。なぜなら、それを完了するのに必要なTは最悪の場合_T = C + a * N_であるためです。ここで、Nはノードの数であり、Caは固定定数です。

あなたの場合、最初にvからwに、次にwからvに2回検索を実行すると、(最悪の場合)_2T_、または_2C + 2a * N_。これは、線形時間要件O(N)も満たします。新しい_C' = 2C_と新しい_a' = 2a_を定義する場合、両方とも_C'_および_a'_も固定定数です。

2
Dan Nissenbaum
int edgeCb( graphPT g, int x, int y )
{
    if ( dist[ y ] > dist[ x ] + 1 ) {
        dist[ y ] = dist[ x ] + 1; // New way
        ways[ y ] = ways[ x ]; // As many ways as it's parent can be reached
    } else if ( dist[ y ] == dist[ x ] + 1 ) {
        ways[ y ] += ways[ x ]; // Another way
    } else {
        // We already found a way and that is the best
        assert( dist[ y ] < g->nv );
    }
    return 1;
}

上記のコードは、この投稿で言及されたあらゆる種類のグラフに対して適切な結果を与えています。基本的には、BFSトラバーサル用のEdgeコールバックです。

dist [start] = 0; way [start] = 1;

残りのすべての頂点dist [x] = numberOfVertices; //これは最大の不満を超えています

BFS(g、start);

Way [end]がゼロでない場合、それはwayの数を表し、dist [end]は最短距離を表します。

Incase way [end] == 0は、最初から最後まで到達できないことを意味します。

これにループの穴があるかどうか教えてください。

2
vamsi

BFSを変更することによる最も簡単なソリューション:

count(v)= 0、count(s)= 1. vのすべての隣接uに対して、if(d(v)+ 1 == d(u))、count(u)+ = count(v)。ここですべてをリセットし、最後の頂点から同じことを行います。

2

このようにできますか

  1. 目的の頂点に到達し、レベルを維持するまでBFSを使用してトラバースします
  2. 宛先レベルに到達したら、次のようにレベルテーブルを使用します

レベルテーブルから、パス内の頂点までの親の数のカウントを逆方向に開始します(最初に目的の頂点になります)。
すべてのステップで、特定のレベルで見つかった個別の親の数を、目的の頂点までの最短パスに乗算します。
パスに落ちるノードのみを考慮してレベルを上げ、レベル0に達するまで各レベルで見つかったdistinct parentの数を掛けます。

これは機能しますか?

0
Rahul Krishna

ここに記載されている適切な説明を確認してください。

https://www.geeksforgeeks.org/number-shortest-paths-unweighted-directed-graph/

簡単に言えば、任意の最短経路アルゴリズムを変更できます。更新ステップが来ると、現在の経路提案がその時点までに見つかった最短経路と同じ長さであるときに以前に発見された最短経路の数のカウンターを増やします。

特定の場合、グラフが重みなしまたはすべてのエッジの重みが一定の場合、最も簡単な方法はBFSを変更することです。

0
jonaprieto