インタビューでこの質問をされましたが、まともな解決策を思い付くことができませんでした。それで、私は彼らに、すべてのサイクルを見つけて、最小の長さのサイクルを選ぶという素朴なアプローチを伝えました。
この問題の効率的な解決策は何か知りたいです。
簡単に変更できます Floyd-Warshallアルゴリズム 。 (グラフ理論にまったく精通していない場合は、それをチェックすることをお勧めします。たとえば、 アルゴリズムの概要 のコピーを入手します)。
従来、i
ごとに_path[i][i] = 0
_を開始します。ただし、代わりに_path[i][i] = INFINITY
_から開始できます。これらのゼロは計算に使用されなかったため、アルゴリズム自体には影響しません(パス_path[i][j]
_は_k == i
_または_k == j
_では変更されないため)。
結局、_path[i][i]
_は、i
を通過する最短サイクルの長さです。したがって、すべてのi
に対してmin(path[i][i])
を見つける必要があります。また、サイクル自体(長さだけでなく)が必要な場合は、通常のパスで行われるのと同じように、アルゴリズムの実行中にk
を記憶することで実行できます。
さらに、 ダイクストラのアルゴリズム を使用して、任意のノードを通過する最短のサイクルを見つけることもできます。この変更されたダイクストラをノードごとに実行すると、Floyd-Warshallの場合と同じ結果が得られます。また、各ダイクストラはO(n^2)
であるため、全体的に同じO(n^3)
の複雑さが得られます。
擬似コードは、ダイクストラのアルゴリズムを単純に変更したものです。
for all u in V:
for all v in V:
path[u][v] = infinity
for all s in V:
path[s][s] = 0
H = makequeue (V) .. using pathvalues in path[s] array as keys
while H is not empty:
u = deletemin(H)
for all edges (u,v) in E:
if path[s][v] > path[s][u] + l(u, v) or path[s][s] == 0:
path[s][v] = path[s][u] + l(u,v)
decreaseKey(H, v)
lengthMinCycle = INT_MAX
for all v in V:
if path[v][v] < lengthMinCycle & path[v][v] != 0 :
lengthMinCycle = path[v][v]
if lengthMinCycle == INT_MAX:
print(“The graph is acyclic.”)
else:
print(“Length of minimum cycle is ”, lengthMinCycle)
時間計算量:O(| V | ^ 3)
質問がTSPと一致するため、巡回セールスマン問題に分枝限定アルゴリズムを使用することもできます。 http://lcm.csa.iisc.ernet.in/dsa/node187.html
以下は、Floyd-Warshellアルゴリズムの簡単な変更です。
V = 4 INF = 999999
def minimumCycleLength(graph): dist = [[0] * V for i in range(V)] for i in range(V): for j in range( V): dist [i] [j] = graph [i] [j]; for k in range(V): for i in range(V): for j in range(V): dist [i] [j] = min(dist [i] [j]、dist [i] [k] + dist [k] [j ]) length = INF for i in range(V): for j in range(V): length = min(length、dist [i ] [j]) 戻り長graph = [ [INF, 1, 1,INF], [INF, INF, 1,INF], [1, INF, INF, 1], [INF, INF, INF, 1] ] length = minimumCycleLength(graph) print length
あなたがしなければならないことは、常に1である各ノードに別の重みを割り当てることです。次に、これらの重みを使用して、あるノードから同じノードへの最短経路アルゴリズムを実行します。ただし、中間パスを検討する際には、実際の重みが負のパスを無視する必要があります。
Tree Edge
、Back Edge
、Down Edge
、およびParent Edge
です。Back Edge
を取得したときに追跡し、長さを取得するための別のカウンターを用意します。詳細については、Algorithms in C++ Part5 - Robert Sedgwick
を参照してください