Menu
Coddy logo textTech

Algorytm Bellmana-Forda

Ostatnia aktualizacja

Algorytm Bellmana-Forda znajduje najkrótszą ścieżkę od węzła źródłowego do każdego innego węzła i w przeciwieństwie do algorytmu Dijkstry działa nawet wtedy, gdy niektóre wagi krawędzi są ujemne. Opiera się na relaksacji metodą siłową: wielokrotnie przegląda każdą krawędź i jeśli przejście przez nią daje krótszą odległość, aktualizuje odległość węzła docelowego. Kliknij odtwarzanie powyżej i zobacz, jak tymczasowe odległości maleją z każdym przebiegiem.

Po V - 1 przebiegach przez wszystkie krawędzie każda najkrótsza ścieżka (która może mieć najwyżej V - 1 krawędzi) jest już znaleziona. Daje to złożoność O(V · E): wolniej niż Dijkstra, ale algorytm obsługuje ujemne wagi i potrafi wykryć cykl o ujemnej wadze (jeśli przebieg numer V wciąż relaksuje krawędź, najkrótsza ścieżka nie istnieje).

Złożoność czasowa i pamięciowa

MiaraZłożonośćUwagi
CzasO(V · E)V − 1 przebiegów przez wszystkie E krawędzi
PamięćO(V)Jedna odległość na węzeł
Ujemne wagiObsługiwaneGłówna przewaga nad algorytmem Dijkstry
Ujemne cykleWykrywalneRelaksacja w przebiegu numer V oznacza cykl

Krok po kroku

KrokCo się dzieje
1Ustaw odległość źródła na 0, a wszystkich pozostałych na nieskończoność.
2Powtórz następny krok V − 1 razy.
3Dla każdej krawędzi (u → v, w) sprawdź, czy dist[u] + w < dist[v].
4Jeśli tak, zrelaksuj ją: ustaw dist[v] = dist[u] + w.
5Zakończ wcześniej, jeśli pełny przebieg niczego nie zmienia.

Przykład krok po kroku

Źródło S w grafie z 4 węzłami S, A, B, C i krawędziami S→A (4), S→B (5), A→C (3), B→A (-3), relaksowanymi w tej kolejności. Odległości startują od S=0, a wszystkie pozostałe od ∞:

PrzebiegOdległości [S, A, B, C]Działanie
Start[0, ∞, ∞, ∞]Odległość źródła to 0, wszystkich pozostałych nieskończoność.
1[0, 2, 5, 7]Relaksuj S→A do 4, S→B do 5, A→C do 7, potem B→A obniża A do 5 + (-3) = 2.
2[0, 2, 5, 5]A→C poprawia teraz C do 2 + 3 = 5; żadna inna krawędź się nie relaksuje.
3[0, 2, 5, 5]Żadna krawędź się nie relaksuje, więc odległości są ostateczne: A kosztuje 2 przez S→B→A.

Kiedy używać algorytmu Bellmana-Forda

Używaj, gdyUnikaj, gdy
Wagi krawędzi mogą być ujemne.Wszystkie wagi są nieujemne (Dijkstra jest szybszy).
Musisz wykrywać cykle o ujemnej wadze.Graf jest ogromny i gęsty: O(V · E) to za wolno.
Graf jest mały lub rzadki.Potrzebujesz tylko jednego zapytania od źródła do celu w dużym grafie.
Potrzebujesz prostego, łatwego w implementacji punktu odniesienia.Wagi są nieujemne, a liczy się czas odpowiedzi.

Bellman-Ford Algorithm: kod

Przejrzysta, gotowa do uruchomienia implementacja algorytmu Bellman-Ford Algorithm w językach: Python, JavaScript, Java, C++, C. Wybierz język, skopiuj kod albo otwórz go od razu w edytorze online Coddy.

Bellman-Ford Algorithm: kod (Python)

Python
1def bellman_ford(vertices, edges, start):2    dist = {v: float("inf") for v in vertices}3    dist[start] = 04    # Relax every edge V-1 times5    for _ in range(len(vertices) - 1):6        for u, v, w in edges:7            if dist[u] + w < dist[v]:8                dist[v] = dist[u] + w9    # One more pass: any improvement means a negative cycle10    for u, v, w in edges:11        if dist[u] + w < dist[v]:12            raise ValueError("Graph contains a negative-weight cycle")13    return dist14
15
16vertices = ["A", "B", "C", "D", "E"]17edges = [18    ("A", "B", 6), ("A", "C", 7), ("B", "D", 5), ("B", "E", -4),19    ("C", "D", -3), ("D", "B", -2), ("E", "D", 7),20]21
22for node, d in bellman_ford(vertices, edges, "A").items():23    print(f"A -> {node}: {d}")
Uruchom ten kod w edytorze Python online

Algorytm Bellmana-Forda: najczęstsze pytania

Jaka jest złożoność czasowa algorytmu Bellmana-Forda?
Algorytm Bellmana-Forda działa w czasie O(V · E): wykonuje V - 1 przebiegów, a każdy przebieg relaksuje wszystkie E krawędzi. To wolniej niż O((V + E) log V) algorytmu Dijkstry i jest to cena obsługi ujemnych wag krawędzi.
Kiedy użyć algorytmu Bellmana-Forda zamiast Dijkstry?
Użyj algorytmu Bellmana-Forda, gdy graf może mieć ujemne wagi krawędzi albo gdy musisz wykrywać cykle o ujemnej wadze. Dijkstra jest szybszy, ale działa poprawnie tylko przy nieujemnych wagach. Typowe praktyczne zastosowanie to wykrywanie arbitrażu walutowego, gdzie ujemne cykle mają znaczenie.
Jak algorytm Bellmana-Forda wykrywa ujemny cykl?
Po V - 1 przebiegach relaksacji wszystkie najkrótsze ścieżki są ustalone, o ile nie ma ujemnego cyklu. Jeśli jeszcze jeden przebieg wciąż może zrelaksować krawędź, to osiągalny jest cykl o ujemnej wadze, a najkrótsze ścieżki są nieokreślone (można by krążyć w nieskończoność i obniżać koszt).
Czym różni się algorytm Bellmana-Forda od algorytmu Floyda-Warshalla?
Algorytm Bellmana-Forda wyznacza najkrótsze ścieżki z jednego źródła w O(V · E), a Floyd-Warshall wyznacza najkrótsze ścieżki między wszystkimi parami w O(V³). W gęstym grafie uruchomienie Bellmana-Forda z każdego źródła kosztuje O(V² · E), więc gdy potrzebujesz każdej pary, Floyd-Warshall jest zwykle lepszym wyborem. Oba obsługują ujemne krawędzie i potrafią zgłosić ujemne cykle.
Dlaczego algorytm Bellmana-Forda potrzebuje dokładnie V - 1 przebiegów?
Każda najkrótsza ścieżka w grafie bez ujemnych cykli używa najwyżej V - 1 krawędzi, bo ścieżka odwiedzająca więcej niż V węzłów musi któryś powtórzyć. Każdy przebieg gwarantuje poprawną relaksację co najmniej jednej kolejnej krawędzi każdej najkrótszej ścieżki, więc V - 1 przebiegów wystarcza, by ustalić je wszystkie. Częste nieporozumienie: więcej przebiegów nie poprawia wyniku, chyba że istnieje ujemny cykl.
Czy algorytm Bellmana-Forda może zakończyć się wcześniej?
Tak. Jeśli pełny przebieg przez wszystkie krawędzie niczego nie relaksuje, każda odległość jest już optymalna i można przerwać przed osiągnięciem V - 1 przebiegów. Ta optymalizacja często znacznie przyspiesza działanie na grafach, które szybko się zbiegają, choć ograniczenie w najgorszym przypadku pozostaje O(V · E).
Ilustracja języków programowania w Coddy

Opanuj algorytmy z Coddy

ZACZNIJ