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