Bellman-Ford Algoritması
Negatif ağırlıklı kenarlarla da en kısa yolları bulan ve negatif döngüleri tespit eden algoritma.
Önce bunlara göz at
#Nasıl çalışır?
Bellman-Ford algoritması, Dijkstra gibi bir başlangıçtan tüm düğümlere en kısa yolları bulur; ama negatif ağırlıklı kenarlarla da doğru çalışır. Negatif ağırlık; geri ödeme, indirim ya da enerji kazancı gibi durumları modeller.
Dijkstra bir düğümü kesinleştirdikten sonra ona bir daha bakmaz. Negatif bir kenar, kesinleşmiş bir düğüme daha sonra daha ucuza ulaşılmasını sağlayabilir; bu yüzden Dijkstra yanlış sonuç verir. Örnek grafta Dijkstra dist[3] = 2 der, oysa 1 → 2 → 3 yolu 4 + (−3) = 1'dir.
Bellman-Ford açgözlü değildir: tüm kenarları V − 1 tur boyunca tekrar tekrar gevşetir. En kısa yol en fazla V − 1 kenar içerdiği için i. turun sonunda en fazla i kenarlı tüm en kısa yollar doğrudur.
V. bir turda hâlâ iyileşen bir mesafe varsa grafta negatif bir döngü vardır: o döngüde dolaştıkça maliyet sürekli düşer ve en kısa yol tanımsız olur. Bellman-Ford bu durumu tespit edebilir.
#Kendin dene
Komşuluk listesi
- 1 → 2 (4), 3 (2)
- 2 → 3 (-3), 4 (2)
- 3 → 5 (3), 6 (5)
- 4 → 7 (2)
- 5 → 4 (-1), 7 (4)
- 6 → 7 (1)
- 7 → —
Kırmızı ağırlıklar negatif. Önce Dijkstra'yı çalıştır ve dist[3] değerine bak, sonra Bellman-Ford ile karşılaştır. 7 → 5 kenarını ekleyince negatif döngü oluşur.
#Adım adım
- 01dist[başlangıç] = 0, diğer tüm mesafeler ∞.
- 02V − 1 tur boyunca: her u → v kenarı için dist[u] + w < dist[v] ise dist[v]'yi güncelle.
- 03Bir turda hiçbir mesafe değişmezse erken dur.
- 04Son olarak bir tur daha dene: bir mesafe hâlâ düşüyorsa negatif döngü var.
#Örnek kod
Aynı algoritma 8 dilde. Her program derlenip çalıştırılarak test edildi ve hepsi aynı çıktıyı veriyor.
INF = float("inf")
# Directed edges (from, to, weight); two of them are negative.
EDGES = [(1, 2, 4), (1, 3, 2), (2, 3, -3), (2, 4, 2), (3, 5, 3),
(3, 6, 5), (4, 7, 2), (5, 4, -1), (5, 7, 4), (6, 7, 1)]
N = 7
def bellman_ford(edges, start):
"""Returns (dist, prev), or None if a negative cycle is reachable."""
dist = {v: INF for v in range(1, N + 1)}
prev = {}
dist[start] = 0
for _ in range(N - 1):
changed = False
for u, v, w in edges:
if dist[u] + w < dist[v]:
dist[v] = dist[u] + w
prev[v] = u
changed = True
if not changed:
break # nothing will change in later rounds either
for u, v, w in edges: # one more round: still improving means a negative cycle
if dist[u] + w < dist[v]:
return None
return dist, prev
dist, prev = bellman_ford(EDGES, 1)
print(" ".join(str(dist[v]) for v in range(1, N + 1)))
path = [7]
while path[-1] != 1:
path.append(prev[path[-1]])
print(" ".join(map(str, reversed(path)))) # uses both negative edges
print("negative cycle" if bellman_ford(EDGES + [(7, 5, -6)], 1) is None else "ok") # 5 -> 7 -> 5 weighs -2#Karmaşıklık
| İşlem | Süre |
|---|---|
| Zaman | O(V · E) |
| Erken durma ile en iyi durum | O(E) |
| Negatif döngü kontrolü | O(E) |
| Bellek | O(V) |
Her tur tüm kenarları dolaşır ve en fazla V − 1 tur gerekir; bu yüzden Dijkstra'nın O((V + E) log V) maliyetinden yavaştır. Negatif kenar yoksa Dijkstra tercih edilir. Kuyruk tabanlı bir iyileştirme olan SPFA ortalamada daha hızlıdır ama en kötü durumu aynıdır.
#Ne zaman kullanılır?
Negatif ağırlıklı graflarda en kısa yol, döviz arbitrajı tespiti (kurların logaritmasıyla negatif döngü aramak), mesafe-vektör yönlendirme protokolleri (RIP) ve Johnson algoritmasının ilk adımı Bellman-Ford kullanır.
#Alıştırma
Soruları cevaplamak ve ilerlemeni kaydetmek için giriş yap.
Kolay
Bellman-Ford'un Dijkstra'ya göre en büyük avantajı nedir?
- 1Negatif ağırlıklı kenarlarla da doğru çalışır
- 2Her zaman daha hızlıdır
- 3Daha az bellek kullanır
- 4Yönsüz graflarda çalışır
V düğümlü bir grafta Bellman-Ford en fazla kaç tur gevşetme yapar?
- 1V − 1
- 2V²
- 3log V
- 4E
Bellman-Ford'un zaman karmaşıklığı nedir?
- 1O(V · E)
- 2O((V + E) log V)
- 3O(V + E)
- 4O(V³)
Orta
V − 1 turdan sonra yapılan ekstra turda bir mesafe hâlâ azalıyorsa bu ne anlama gelir?
- 1Başlangıçtan ulaşılabilen bir negatif döngü var
- 2Graf bağlı değil
- 3Algoritma yeterince tur yapmadı
- 4Bir kenar iki kez sayıldı
Zor
Bir turda hiçbir mesafe değişmezse neden erken durulabilir?
- 1Sonraki turlar aynı kenarları aynı değerlerle gevşetir; hiçbir şey değişmez
- 2Negatif kenar kalmadığı için
- 3Tüm düğümler ziyaret edildiği için
- 4Kuyruk boşaldığı için