これが アルゴリズム設計マニュアル の練習問題です。
与えられた無向グラフG =(V、E)に三角形または長さ3のサイクルが含まれているかどうかを判断する問題を考えます。
(a)O(| V | ^ 3)を指定して、三角形が存在する場合はそれを見つけます。
(b)時間内に実行されるようにアルゴリズムを改善しますO(| V |・| E |)。 | V | ≤| E |。
これらの境界により、隣接行列とGの隣接リスト表現の間で変換する時間が得られることに注意してください。
これが私の考えです:
(a)グラフが隣接リストとして与えられている場合、O(| V | ^ 2)によってリストを行列に変換できます。それから私はします:
for (int i = 0;i < n;i++)
for (int j = i+1;j < n;j++)
if (matrix[i][j] == 1)
for (int k = j+1;k < n;k++)
if (matrix[i][k] == 1 && matrix[j][k] == 1)
return true;
これにより、三角形をテストするためのO(| V | ^ 3)が得られます。
(b)私の最初の直感は、グラフが隣接リストとして指定されている場合、bfsを実行することです。クロスエッジが見つかった場合は常に、たとえばif y-x is a cross Edge
、それから私はcheck whether parent[y] == parent[x], if true, then a triangle is found
。
私の考えが正しいかどうか誰かに教えてもらえますか?
これ(b)についても、その複雑さはわかりません。 O(| V | + | E |)である必要がありますか?
O(| V | * | E |)でどうすればよいですか?
可能なO(|V||E|)
ソリューションは、(a)の総当たりの考え方と同じです。
for each Edge (u, v):
for each vertex w:
if (v, w) is an Edge and (w, u) is an Edge:
return true
return false
すべてのエッジをチェック、およびnotすべての頂点のペア-三角形を形成する別の頂点と-エッジと頂点が実行可能なソリューションを形成するかどうかを判断するのに十分な情報です。
BFSソリューションのカウンターの例:
A
/ | \
/ | \
B C D
| | |
| | |
F---G---H
| |
---------
(F, H) is also an Edge
ご了承ください father[F] != father[G] != father[H]
、したがって、アルゴリズムはfalseを返しますが、それでも(F、G、H)は実行可能なソリューションです!
隣接行列がある場合は、行列を2乗し、元の行列と正方行列のゼロ以外のエントリが同じ場所にあるかどうかを確認することで、三角形を見つけることができます。
素朴な行列乗算には時間がかかりますがO(n^3)
、より高速な行列乗算アルゴリズムがあります。最もよく知られているものの1つが、O(n^2.4)
時間で実行される Coppersmith-Winograd アルゴリズムです。つまり、アルゴリズムは次のようになります。
O(V^2)
時間を使用して、隣接行列に変換します。O(V^2.4)
時間を使用して、隣接行列の2乗を計算します。O(V^2)
時間を使用して、ゼロ以外のエントリが一致するかどうか行列をチェックします。O(V)
時間を使用して、両方の既知のノードに共通する3番目のノードを絞り込みます。つまり、全体的にO(V^2.4)
時間かかります。より正確には、行列の乗算に時間がかかります。このアルゴリズムとif-any-Edge-end-points-have-a-common-neighborアルゴリズムを動的に切り替えることができます そのamitが回答で説明しています これをO(V min(V^1.4, E))
に改善します。
これが 問題をより詳細に説明する論文 です。
これは、理論上の発見に依存してこの問題がいかに巧妙であるかということです。行列の乗算が実際に2次式であるという推測が真であることが判明した場合、O(V^2)
またはO(V^2 log(V))
のような非常に良い時間範囲が得られます。しかし、量子コンピューターがうまくいったら、私たちはできるでしょう それよりもさらに良い (O(V^1.3)
のようなもの)!
これが私が思うことです:
上記のように、元のBFSソリューションは正しくありません。しかし、DFSを変更できます。 DFSの各頂点にアクセスするときに、訪問したノードに番号を割り当てます。ここで、頂点に到達した場合(質問ではクロスエッジを見たが、無向グラフには何もない)、その隣接リストをチェックし、1つの頂点が検出された(処理されていない、発生しない)と想定し、その番号をチェックします。 。差が2の場合、長さ3のサイクルがあります。
私は本当に気に入っています このブログ投稿で説明されている行列乗算ソリューション 。
A =隣接行列とする
問題は、行列の乗算が遅いことです。ただし、GPGPUを使用して行列の乗算を実行でき、GPUを含む最新のアーキテクチャーで高性能のソリューションを使用できます。