web-dev-qa-db-ja.com

無向の重み付けされていないグラフで指定された長さのパスの数を見つける

パスの「長さ」は、パス内のエッジの数です。

ソースと宛先の頂点が与えられた場合、指定された長さのソース頂点から宛先頂点までのパスの数を見つけたい)k。

  • 各頂点には何度でもアクセスできるため、aからbへのパスが次のようになる場合:a -> c -> b -> c -> bは有効と見なされます。これは、サイクルが存在する可能性があり、目的地を複数回通過できることを意味します。

  • 2つの頂点を複数のエッジで接続できます。したがって、頂点a頂点bが2つのエッジで接続されている場合、エッジ1を介したパスa -> bとエッジ2を介したa -> bは異なると見なされます。

  • 頂点の数Nは<= 70であり、パスの長さであるKは<= 10 ^ 9です。

  • 答えは非常に大きくなる可能性があるため、いくつかの数を法として報告されます。

これが私がこれまでに考えたことです:

breadth-first-search を使用できます。頂点を訪問済みとしてマークせずに、各反復で、そのパスに必要なエッジ 'n_e'の数を追跡します product 'p'は、パス内の各エッジが持つ重複エッジの数です。

n_eがkより大きい場合、検索検索は終了する必要があります。n_eがkに等しい宛先に到達した場合、検索を終了し、pをパス。

最短パスは必要なく、幅優先探索で使用されるQのサイズでは不十分な場合があるため、幅優先探索の代わりに深さ優先探索を使用できると思います。

私が考えている2番目のアルゴリズムは、 Floyd Warshall's Algorithm using this approachに似ています。最短経路は必要ないので、これが正しいかどうかはわかりません。

最初のアルゴリズムで私が抱えている問題は、「K」が最大1000000000になる可能性があることです。つまり、検索は10 ^ 9のエッジがあり、n_eのエッジ数が各レベルで1だけ増加するまで実行されます。これは、非常に大きくなります。遅いし、大きな入力で終了するかどうかはわかりません。

したがって、この問題を解決するには別のアプローチが必要です。どんな助けでも大歓迎です。

13
2147483647

だから、これは私がこれのために覚えている気の利いたグラフ理論のトリックです。

隣接行列Aを作成します。どこ A[i][j]は、ijの間にエッジがある場合は1、それ以外の場合は0です。

その場合、kiの間の長さjのパスの数は[i][j] A ^ kのエントリ。

したがって、この問題を解決するには、Aを作成し、行列の乗算を使用してA ^ kを作成します(ここでは、べき乗を行うための通常のトリックが適用されます)。次に、必要なエントリを検索します。

編集:オーバーフローの問題を回避するために、行列乗算内でモジュラー演算を実行する必要がありますが、それははるかに小さな詳細です。

36
Dennis Meng

実際、A ^ kの[i] [j]エントリは、各単純なグラフで、「パス」ではなく、まったく異なる「ウォーク」を示しています。 「数学的帰納法」で簡単に証明できます。ただし、主要な問題は、特定のグラフでまったく異なる「パス」を見つけることです。解決すべきアルゴリズムはかなり異なりますが、上限は次のとおりです。

(n-2)(n-3) ...(n-k)ここで、「k」はパスの長さを示す指定されたパラメーターです。

2
Amir

上記の回答にさらにいくつかのコンテンツを追加しましょう(これは私が直面した拡張された問題であるため)。拡張された問題は

指定された無向ツリーで長さkのパスの数を見つけます。

解決策は、グラフの与えられた隣接行列Aに対して単純ですGはAを見つけますk-1 およびAk 次に、対角線より上(または下)の要素の1sの数を数えます。

pythonコードも追加しましょう。

import numpy as np

def count_paths(v, n, a):
    # v: number of vertices, n: expected path length
    paths = 0    
    b = np.array(a, copy=True)

    for i in range(n-2):
        b = np.dot(b, a)

    c = np.dot(b, a)
    x = c - b

    for i in range(v):
        for j in range(i+1, v):
            if x[i][j] == 1:
                paths = paths + 1

    return paths

print count_paths(5, 2, np.array([
                np.array([0, 1, 0, 0, 0]),
                np.array([1, 0, 1, 0, 1]),
                np.array([0, 1, 0, 1, 0]),
                np.array([0, 0, 1, 0, 0]),
                np.array([0, 1, 0, 0, 0])
            ])
1
Madhusoodan P