このタスクは、行列の乗算によって解決されます。
0 と 1 を含む行列n
xを作成します ( からへのパスがある場合、セルに対して 1 )。この行列をそれ自体で乗算します(高速行列累乗の使用を検討してください)。次に、マトリックスのセルには、から始まり、で終わる長さのパスの数があります。n
mat[i][j]
i
j
k
mat[i][j]
k
i
j
注: 高速行列累乗は基本的に高速累乗と同じですが、代わりに数値を乗算して行列を乗算します。
注 2:n
はグラフ内の頂点の数であると仮定します。次に、ここで提案するアルゴリズムは、時間の複雑さ O(log k * n 3 ) で実行され、メモリの複雑さは O(n 2 ) です。ここで説明されているように、最適化された行列乗算を使用すると、もう少し改善できます。その場合、時間計算量は O(log k * n log 2 7 ) になります。
編集Antoine の要求に応じて、このアルゴリズムが実際に機能する理由を説明します。
アルゴリズムを帰納法で証明します。帰納法の基礎は明らかです。最初に、行列に長さ 1 のパスの数があります。
k
行列を の累乗にすると、 の累乗k
まで、との間のmat[i][j]
長さのパスの数があると仮定しましょう。k
i
j
次のステップを考えてみましょうk + 1
。k + 1
長さのすべてのパスは、長さのプレフィックスk
ともう 1 つのエッジで構成されることは明らかです。これは基本的に、長さのパスが次の式k + 1
で計算できることを意味します (ここではmat_pow_k
、行列を 1 乗したものを示しますk
)
num_paths(x, y, k + 1) = sum i=0 i<n mat_pow_k[x][i] * mat[i][y]
繰り返しますn
が、グラフ内の頂点の数です。これを理解するには少し時間がかかるかもしれませんが、基本的に、初期行列のmat[i][y]
セルには と の間に直接エッジがある場合にのみ1 がx
ありy
ます。そして、長さ のパスを形成するために、そのようなエッジのすべての可能な接頭辞を数えますk + 1
。
しかし、私が最後に書いたのは、実際には のk + 1
st 乗を計算することですmat
。これは、帰納法と私のステートメントのステップを証明します。