Floyd-Warshall: Kürzeste Wege zwischen allen Knotenpaaren
Füllen Sie die Distanzmatrix für alle Knotenpaare mit dem Floyd-Warshall-Algorithmus mit drei verschachtelten Schleifen und wenden Sie ihn an, um die kleinste Anzahl von Sprüngen zwischen allen Knotenpaaren zu finden.
Floyd-Warshall: Kürzeste Wege zwischen allen Knotenpaaren ist eine kostenlose Coding Interview Prep-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Coding Interview Prep-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Coding Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Kürzeste Wege zwischen allen Knotenpaaren
Floyd-Warshall berechnet kürzeste Wege zwischen jedem Knotenpaar in einem gewichteten Graphen – auch in Graphen mit negativen Kantengewichten (aber nicht mit negativen Zyklen). Dijkstra von jeder Quelle auszuführen kostet O(V × (V+E) log V); Floyd-Warshall läuft unabhängig von der Kantendichte in O(V³). Für dichte Graphen mit V ≤ 500 ist Floyd-Warshall oft einfacher und ähnlich schnell.
Die zentrale Idee: Zwischenknoten
Floyd-Warshalls zentrale Erkenntnis: dp[i][j][k] = kürzester Pfad von i nach j, der nur Knoten aus {0, 1, ..., k} als Zwischenknoten verwendet. Entweder verwendet der kürzeste Pfad den Knoten k als Zwischenknoten oder nicht. Falls ja: dp[i][j][k] = dp[i][k][k-1] + dp[k][j][k-1]. Falls nicht: dp[i][j][k] = dp[i][j][k-1]. Da die dritte Dimension nur vorwärts fortschreitet, kann sie eliminiert werden – wir aktualisieren direkt an Ort und Stelle.
Initialisierung der Distanzmatrix
Beginnen Sie mit einer V×V-Matrix: dist[i][i] = 0 (Entfernung eines Knotens zu sich selbst), dist[i][j] = weight für direkte Kanten und dist[i][j] = inf für Nichtkanten. Iterieren Sie dann über alle Zwischenknoten k und aktualisieren Sie die Paare (i, j). Die äußere Schleife über k muss zuerst kommen, damit wir Pfade über eine zunehmend größere Menge zulässiger Zwischenknoten korrekt aufbauen.
def floyd_warshall(V, edges):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
for i in range(V):
dist[i][i] = 0
for u, v, w in edges:
dist[u][v] = w # directed graph
for k in range(V): # intermediate node
for i in range(V):
for j in range(V):
if dist[i][k] + dist[k][j] < dist[i][j]:
dist[i][j] = dist[i][k] + dist[k][j]
return distVollständige Implementierung mit Beispiel
Verfolgen wir Floyd-Warshall an einem Graphen mit 4 Knoten. Nach der Verarbeitung jedes Zwischenknotens wird die Matrix um kürzere Pfade ergänzt, die über den Knoten k führen. Der Algorithmus verarbeitet mehrere Sprünge ganz natürlich, indem er kürzeste Pfade schrittweise aufbaut.
def floyd_warshall(V, edges):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
for i in range(V):
dist[i][i] = 0
for u, v, w in edges:
dist[u][v] = w
for k in range(V):
for i in range(V):
for j in range(V):
if dist[i][k] != INF and dist[k][j] != INF:
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
return dist
V = 4
edges = [(0,1,3),(0,2,7),(1,2,1),(1,3,5),(2,3,2)]
dist = floyd_warshall(V, edges)
for row in dist:
print([x if x != float('inf') else 'INF' for x in row])Negative Zyklen erkennen
Überprüfen Sie nach der Ausführung von Floyd-Warshall die Hauptdiagonale: Wenn ein Wert dist[i][i] < 0 ist, gibt es einen negativen Zyklus, der durch den Knoten i verläuft. Das liegt daran, dass ein negativer Zyklus ermöglicht, i von i aus mit negativen Kosten zu erreichen. Wenn kein negativer Zyklus existiert, bleiben alle Diagonaleinträge 0.
def has_negative_cycle_fw(V, edges):
dist = floyd_warshall(V, edges)
for i in range(V):
if dist[i][i] < 0:
return True # negative cycle through node i
return False
# Negative cycle: 0->1->2->0 with weights 1,-3,1 (sum=-1)
edges_neg = [(0,1,1),(1,2,-3),(2,0,1)]
print(has_negative_cycle_fw(3, edges_neg)) # TruePfadrekonstruktion
Um den tatsächlichen Pfad von i nach j zu rekonstruieren, verwalten Sie eine next[i][j]-Matrix: Initialisieren Sie sie für direkte Kanten mit next[i][j] = j. Bei einer Aktualisierung über den Zwischenknoten k setzen Sie next[i][j] = next[i][k]. Um den Pfad wiederherzustellen, beginnen Sie bei i und folgen den next-Zeigern, bis j erreicht ist. Dies benötigt O(V²) Speicherplatz und O(V) für jede Pfadrekonstruktion.
def fw_with_path(V, edges):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
nxt = [[None]*V for _ in range(V)]
for i in range(V): dist[i][i] = 0
for u, v, w in edges:
dist[u][v] = w; nxt[u][v] = v
for k in range(V):
for i in range(V):
for j in range(V):
if dist[i][k] + dist[k][j] < dist[i][j]:
dist[i][j] = dist[i][k] + dist[k][j]
nxt[i][j] = nxt[i][k]
return dist, nxt
def get_path(nxt, i, j):
if nxt[i][j] is None: return []
path = [i]
while i != j:
i = nxt[i][j]; path.append(i)
return pathTransitive Hülle
Eine einfachere Variante: Die transitive Hülle beantwortet für alle Paare die Frage „Ist Knoten j von Knoten i aus erreichbar?“. Ersetzen Sie Distanzen durch boolesche Werte: reach[i][j] = reach[i][j] or (reach[i][k] and reach[k][j]). Dies ist Floyd-Warshall mit booleschem OR statt Addition und Minimum. Initialisieren Sie reach[i][i] = True und setzen Sie reach[i][j] = True für direkte Kanten.
def transitive_closure(V, edges):
reach = [[False]*V for _ in range(V)]
for i in range(V):
reach[i][i] = True
for u, v, _ in edges:
reach[u][v] = True
for k in range(V):
for i in range(V):
for j in range(V):
reach[i][j] = reach[i][j] or (reach[i][k] and reach[k][j])
return reach
edges = [(0,1,1),(1,2,1)]
R = transitive_closure(3, edges)
print(R[0][2]) # True (0 can reach 2 via 0->1->2)Komplexität und Einsatzgebiete
Floyd-Warshall: O(V³) Zeit, O(V²) Speicherplatz. Für dichte Graphen (E ≈ V²) mit V ≤ 300 ist dieser Algorithmus schneller als Dijkstra V-mal auszuführen (in diesem Fall ebenfalls O(V³)). Für dünn besetzte Graphen mit V = 1000 und E = 3000 kosten V Dijkstra-Ausführungen O(V×E×log V) ≈ 33M, während Floyd-Warshall O(V³) = 10⁹ kostet – Dijkstra ist schneller. Wissen Sie, wann welcher Algorithmus geeignet ist.
Minimale Anzahl von Hops zwischen allen Knotenpaaren
Setzen Sie alle Kantengewichte auf 1 (oder verwenden Sie eine boolesche Adjazenzmatrix mit Floyd-Warshall, wobei Sie Addition statt Minimum verwenden): dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]). Damit wird die minimale Anzahl von Hops zwischen allen Knotenpaaren berechnet – das Ergebnis einer BFS für alle Knotenpaare, aber in einem einzigen Floyd-Warshall-Durchlauf mit O(V³).
def min_hops_all_pairs(V, adj_list):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
for i in range(V):
dist[i][i] = 0
for j in adj_list[i]:
dist[i][j] = 1
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])
return dist
adj = [[1,2],[2],[3],[],[]]
print(min_hops_all_pairs(5, adj)[0]) # [0, 1, 1, 2, INF]Interviewkontext: Wenn Interviewer nach Floyd-Warshall fragen
Floyd-Warshall kommt in Interviews bei Aufgaben vor, die Folgendes betreffen: (1) Distanzen zwischen allen Knoten eines kleinen Graphen, (2) das Ermitteln eines Zyklus mit einem negativen Gesamtgewicht, (3) die Berechnung kürzester Wege in Problemen zur Constraint-Propagation und (4) Aufgaben, die ausdrücklich Lösungen mit O(V³) verlangen, wobei V ≤ 200 gilt. Erwähnen Sie in einem Interview immer die Struktur mit drei Schleifen sowie die Voraussetzung, dass keine negativen Zyklen vorhanden sein dürfen, damit der Algorithmus korrekt ist.
Ungerichtete Graphen mit Floyd-Warshall
Fügen Sie bei ungerichteten Graphen für jede Kante beide Richtungen hinzu: dist[u][v] = dist[v][u] = weight. Der Rest des Algorithmus bleibt identisch. Die resultierende Matrix ist symmetrisch: dist[i][j] == dist[j][i] für alle Knotenpaare. Achten Sie bei der Initialisierung darauf, nicht versehentlich gerichtete Kanten zuzuweisen – ungerichtete Kanten müssen vor Ausführung der drei Schleifen in beiden Richtungen zur Anfangsmatrix hinzugefügt werden.
def fw_undirected(V, edges):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
for i in range(V): dist[i][i] = 0
for u, v, w in edges:
dist[u][v] = w
dist[v][u] = w # both directions for undirected
for k in range(V):
for i in range(V):
for j in range(V):
if dist[i][k] + dist[k][j] < dist[i][j]:
dist[i][j] = dist[i][k] + dist[k][j]
return distSchnelltest
Testen Sie Ihr Verständnis der Konzepte aus dieser Lektion im Bereich Data Structures & Algorithms — Coding Interview Prep.
Zusammenfassung der Lektion
In dieser Lektion haben Sie gelernt: Floyd-Warshall berechnet die kürzesten Wege zwischen allen Knotenpaaren mit drei verschachtelten Schleifen und der Rekurrenz dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]), negative Zyklen lassen sich erkennen, indem nach Abschluss geprüft wird, ob ein dist[i][i] < 0 ist, und der Algorithmus benötigt O(V³) Zeit und O(V²) Speicherplatz. Als Nächstes sehen wir uns Anwendungen kürzester Wege mit Network Delay Time sowie Techniken zur Pfadrekonstruktion an.
Häufig gestellte Fragen
Ist die Lektion „Floyd-Warshall: Kürzeste Wege zwischen allen Knotenpaaren“ kostenlos?
Ja — der vollständige Text von „Floyd-Warshall: Kürzeste Wege zwischen allen Knotenpaaren“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Coding Interview Prep-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Coding Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Floyd-Warshall: Kürzeste Wege zwischen allen Knotenpaaren“?
Füllen Sie die Distanzmatrix für alle Knotenpaare mit dem Floyd-Warshall-Algorithmus mit drei verschachtelten Schleifen und wenden Sie ihn an, um die kleinste Anzahl von Sprüngen zwischen allen Knote… Du übst Coding Interview Prep mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Coding Interview Prep zu starten?
Keine Vorkenntnisse erforderlich. Coding Interview Prep auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.
Wie lange dauert die Lektion „Floyd-Warshall: Kürzeste Wege zwischen allen Knotenpaaren“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Coding Interview Prep-Lektion Code schreiben und ausführen?
Ja. Jede Coding Interview Prep-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Dijkstras Algorithmus mit einer Priority Queue
- Bellman-Ford und negative Zyklen
- Floyd-Warshall: Kürzeste Wege zwischen allen Knotenpaaren
- Network Delay Time und Pfadrekonstruktion