AlgoDatSoSe26/praktika/08_kuerzeste_wege/aufgabe2_bellman_ford.py
2026-06-16 11:10:54 +02:00

83 lines
2.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from vorlesung.L08_graphen.graph import AdjacencyListGraph
# Korrigierte Kantenliste (Vorlesungsbeispiel).
# Hinweis: Das Arbeitsblatt enthält c->b:-2, c->e:5, d->c:-5, e->c:4
# diese Werte erzeugen einen negativen Zyklus (b->c->b: 1-2=-1) im
# Basisgraphen und müssen in der Aufgabenstellung korrigiert werden.
# Korrekte Werte (kein Vorzyklus, Ergebnis: b=7, c=2, d=4, e=6):
EDGES = [
('a', 'b', 9),
('a', 'd', 4),
('b', 'c', 1),
('b', 'd', 2),
('c', 'b', 5), # war -2 im Entwurf
('c', 'e', 4), # war 5 im Entwurf
('d', 'c', -2), # war -5 im Entwurf
('d', 'e', 2),
]
def bellman_ford(graph, start_name):
"""Bellman-Ford: kürzeste Wege mit Erkennung negativer Zyklen.
Gibt (distance_map, predecessor_map, has_negative_cycle) zurück.
|V|-1 Relaxationsdurchläufe über alle Kanten, dann ein Prüfdurchlauf.
"""
distance_map = {}
predecessor_map = {}
for v in graph.all_vertices():
distance_map[v] = float('inf')
predecessor_map[v] = None
start = graph.get_vertex(start_name)
distance_map[start] = 0
n = len(list(graph.all_vertices()))
for _ in range(n - 1):
for src_name, dst_name, weight in graph.all_edges():
src = graph.get_vertex(src_name)
dst = graph.get_vertex(dst_name)
if distance_map[src] + weight < distance_map[dst]:
distance_map[dst] = distance_map[src] + weight
predecessor_map[dst] = src
# Prüfdurchlauf: jede weitere Verbesserung zeigt einen negativen Zyklus
has_negative_cycle = False
for src_name, dst_name, weight in graph.all_edges():
src = graph.get_vertex(src_name)
dst = graph.get_vertex(dst_name)
if distance_map[src] + weight < distance_map[dst]:
has_negative_cycle = True
break
return distance_map, predecessor_map, has_negative_cycle
# --- a) + b) Basisgraph ---
g = AdjacencyListGraph()
for v in ['a', 'b', 'c', 'd', 'e']:
g.insert_vertex(v)
for src, dst, w in EDGES:
g.connect(src, dst, w)
dist, pred, neg_cycle = bellman_ford(g, 'a')
print(f"Negativer Zyklus: {neg_cycle}")
print("Kürzeste Distanzen:")
for name in ['a', 'b', 'c', 'd', 'e']:
v = g.get_vertex(name)
pfad = g.path(name, pred)
print(f" {name}: d={dist[v]}, Pfad: {' -> '.join(pfad)}")
# --- d) Komplexität ---
v_count = len(list(g.all_vertices()))
e_count = len(g.all_edges())
print(f"\n|V| = {v_count}, |E| = {e_count}")
# --- c) Negativer Zyklus ---
print("\n--- Mit negativem Zyklus (e -> b, Gewicht -8) ---")
g.connect('e', 'b', -8)
dist2, pred2, neg_cycle2 = bellman_ford(g, 'a')
print(f"Negativer Zyklus: {neg_cycle2}")
# Betroffener Zyklus: b -> c -> e -> b (1 + 4 + (-8) = -3 < 0)