Musterlösung Praktikum 8
This commit is contained in:
parent
586a52f9a5
commit
1692129d89
84
praktika/08_kuerzeste_wege/aufgabe1_dijkstra.py
Normal file
84
praktika/08_kuerzeste_wege/aufgabe1_dijkstra.py
Normal file
@ -0,0 +1,84 @@
|
||||
import time
|
||||
from vorlesung.L08_graphen.graph import AdjacencyListGraph
|
||||
|
||||
# AoC 2024, Tag 16 – erstes Beispiel-Labyrinth (Antwort: 7036)
|
||||
GRID = """\
|
||||
###############
|
||||
#.......#....E#
|
||||
#.#.###.#.###.#
|
||||
#.....#.#...#.#
|
||||
#.###.#####.#.#
|
||||
#.#.#.......#.#
|
||||
#.#.#####.###.#
|
||||
#...........#.#
|
||||
###.#.#####.#.#
|
||||
#...#.....#.#.#
|
||||
#.#.#.###.#.#.#
|
||||
#.....#...#.#.#
|
||||
#.###.#.#.#.#.#
|
||||
#S..#.....#...#
|
||||
###############""".strip().split('\n')
|
||||
|
||||
# Richtungen: 0=N, 1=O, 2=S, 3=W (O = Ost = Startrichtung des Rentiers)
|
||||
DR = [-1, 0, 1, 0]
|
||||
DC = [0, 1, 0, -1]
|
||||
|
||||
|
||||
def build_graph(grid):
|
||||
g = AdjacencyListGraph()
|
||||
rows, cols = len(grid), len(grid[0])
|
||||
start = end = None
|
||||
|
||||
for r in range(rows):
|
||||
for c in range(cols):
|
||||
if grid[r][c] == '#':
|
||||
continue
|
||||
if grid[r][c] == 'S':
|
||||
start = (r, c)
|
||||
elif grid[r][c] == 'E':
|
||||
end = (r, c)
|
||||
for d in range(4):
|
||||
g.insert_vertex(f"{r},{c},{d}")
|
||||
|
||||
for r in range(rows):
|
||||
for c in range(cols):
|
||||
if grid[r][c] == '#':
|
||||
continue
|
||||
for d in range(4):
|
||||
src = f"{r},{c},{d}"
|
||||
# Vorwärtsbewegen (Kosten 1)
|
||||
nr, nc = r + DR[d], c + DC[d]
|
||||
if 0 <= nr < rows and 0 <= nc < cols and grid[nr][nc] != '#':
|
||||
g.connect(src, f"{nr},{nc},{d}", 1)
|
||||
# Drehen links und rechts (Kosten 1000 je Drehung)
|
||||
g.connect(src, f"{r},{c},{(d - 1) % 4}", 1000)
|
||||
g.connect(src, f"{r},{c},{(d + 1) % 4}", 1000)
|
||||
|
||||
return g, start, end
|
||||
|
||||
|
||||
# --- a) + b) Graph aufbauen und Dijkstra ausführen ---
|
||||
|
||||
g, start, end = build_graph(GRID)
|
||||
v_count = len(list(g.all_vertices()))
|
||||
e_count = len(g.all_edges())
|
||||
print(f"Graph: |V| = {v_count}, |E| = {e_count}")
|
||||
|
||||
start_state = f"{start[0]},{start[1]},1" # Startposition, Blickrichtung Ost (1)
|
||||
dist_map, pred_map = g.dijkstra(start_state)
|
||||
|
||||
# Bestes Zielfeld: E in beliebiger Richtung (4 zulässige Zielzustände)
|
||||
end_vertices = [g.get_vertex(f"{end[0]},{end[1]},{d}") for d in range(4)]
|
||||
best_end = min(end_vertices, key=lambda v: dist_map[v])
|
||||
print(f"Gesamtkosten: {dist_map[best_end]}") # Erwartung: 11048
|
||||
|
||||
pfad = g.path(best_end.value, pred_map)
|
||||
print(f"Pfad: {len(pfad)} Zustände ({len(pfad) - 1} Schritte)")
|
||||
print("Erste Schritte:", " -> ".join(pfad[:5]), "...")
|
||||
print("Letzte Schritte: ...", " -> ".join(pfad[-3:]))
|
||||
|
||||
# --- c) Laufzeitmessung ---
|
||||
t0 = time.perf_counter()
|
||||
g.dijkstra(start_state)
|
||||
t1 = time.perf_counter()
|
||||
print(f"\nLaufzeit (Beispiel): {(t1 - t0) * 1000:.3f} ms")
|
||||
82
praktika/08_kuerzeste_wege/aufgabe2_bellman_ford.py
Normal file
82
praktika/08_kuerzeste_wege/aufgabe2_bellman_ford.py
Normal file
@ -0,0 +1,82 @@
|
||||
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)
|
||||
Loading…
x
Reference in New Issue
Block a user