Musterlösung Praktikum 7
This commit is contained in:
parent
646b9c6881
commit
c478317d76
89
praktika/07_graph/aufgabe1_bfs.py
Normal file
89
praktika/07_graph/aufgabe1_bfs.py
Normal file
@ -0,0 +1,89 @@
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
|
||||
from vorlesung.L08_graphen.graph import AdjacencyListGraph
|
||||
|
||||
GRID = [
|
||||
"Sabqponm",
|
||||
"abcryxxl",
|
||||
"accszExk",
|
||||
"acctuvwj",
|
||||
"abdefghi",
|
||||
]
|
||||
|
||||
def height(ch):
|
||||
if ch == 'S': return ord('a')
|
||||
if ch == 'E': return ord('z')
|
||||
return ord(ch)
|
||||
|
||||
def build_graph(grid):
|
||||
rows = len(grid)
|
||||
cols = len(grid[0])
|
||||
g = AdjacencyListGraph()
|
||||
for r in range(rows):
|
||||
for c in range(cols):
|
||||
g.insert_vertex(f"{r}_{c}")
|
||||
for r in range(rows):
|
||||
for c in range(cols):
|
||||
for dr, dc in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
|
||||
nr, nc = r + dr, c + dc
|
||||
if 0 <= nr < rows and 0 <= nc < cols:
|
||||
if height(grid[nr][nc]) - height(grid[r][c]) <= 1:
|
||||
g.connect(f"{r}_{c}", f"{nr}_{nc}")
|
||||
return g, rows, cols
|
||||
|
||||
def find_start_end(grid):
|
||||
start = end = None
|
||||
for r, row in enumerate(grid):
|
||||
for c, ch in enumerate(row):
|
||||
if ch == 'S': start = f"{r}_{c}"
|
||||
if ch == 'E': end = f"{r}_{c}"
|
||||
return start, end
|
||||
|
||||
def solve(grid, label="Beispielgelände"):
|
||||
g, rows, cols = build_graph(grid)
|
||||
start, end = find_start_end(grid)
|
||||
|
||||
t0 = time.perf_counter()
|
||||
dist_map, pred_map = g.bfs(start)
|
||||
t1 = time.perf_counter()
|
||||
|
||||
pfad = g.path(end, pred_map)
|
||||
|
||||
def fmt(node):
|
||||
r, c = node.split("_")
|
||||
return f"({r},{c})"
|
||||
|
||||
print(f"=== {label} ===")
|
||||
print(f"|V| = {rows * cols}, |E| <= {rows * cols * 4} (real |E| gezählt separat)")
|
||||
print(f"Pfadlänge: {len(pfad) - 1} Schritte")
|
||||
print(f"Pfad: {' -> '.join(fmt(n) for n in pfad)}")
|
||||
print(f"BFS-Laufzeit: {(t1 - t0) * 1000:.4f} ms")
|
||||
print()
|
||||
return rows * cols, t1 - t0
|
||||
|
||||
# --- a) Modellierung ---------------------------------------------------------
|
||||
# Adjazenzliste ist besser geeignet: Das Grid ist licht (sparse).
|
||||
# Jeder Knoten hat maximal 4 Nachbarn => |E| <= 4|V|.
|
||||
# Eine Adjazenzmatrix hätte |V|^2 Einträge; für ein 41x122-Grid wären das
|
||||
# über 25 Millionen Einträge, obwohl nur ~4*|V| davon belegt wären.
|
||||
|
||||
# --- b) Pfadsuche -------------------------------------------------------------
|
||||
v_small, t_small = solve(GRID, "Beispielgelände (8x5)")
|
||||
|
||||
# --- c) AoC-Karte (optional) --------------------------------------------------
|
||||
if len(sys.argv) > 1 and os.path.exists(sys.argv[1]):
|
||||
with open(sys.argv[1]) as f:
|
||||
aoc_grid = [line.rstrip() for line in f if line.strip()]
|
||||
v_large, t_large = solve(aoc_grid, f"AoC-Karte ({len(aoc_grid)}x{len(aoc_grid[0])})")
|
||||
ratio_v = v_large / v_small
|
||||
ratio_t = t_large / t_small if t_small > 0 else float('inf')
|
||||
print(f"Verhältnis |V|: {ratio_v:.1f}x")
|
||||
print(f"Verhältnis Laufzeit: {ratio_t:.1f}x")
|
||||
print(f"Lineares Wachstum bestätigt: {'ja' if abs(ratio_t / ratio_v - 1) < 0.5 else 'nein'}")
|
||||
|
||||
# --- d) Optional: bester Startpunkt (AoC Teil 2) ------------------------------
|
||||
# Hinweis: Statt BFS von jedem 'a'-Feld zu starten, dreht man den Graphen um
|
||||
# und startet eine einzige BFS von E rückwärts. Der erste erreichte 'a'-Knoten
|
||||
# liefert den kürzesten Pfad.
|
||||
52
praktika/07_graph/aufgabe2_dfs.py
Normal file
52
praktika/07_graph/aufgabe2_dfs.py
Normal file
@ -0,0 +1,52 @@
|
||||
from vorlesung.L08_graphen.graph import AdjacencyListGraph
|
||||
|
||||
DEPENDENCIES = {
|
||||
"main": ["parser", "codegen"],
|
||||
"parser": ["lexer", "ast"],
|
||||
"codegen": ["ast", "optimizer"],
|
||||
"optimizer": ["utils"],
|
||||
"ast": ["utils"],
|
||||
"lexer": [],
|
||||
"utils": [],
|
||||
}
|
||||
|
||||
# --- a) Graph aufbauen -------------------------------------------------------
|
||||
g = AdjacencyListGraph()
|
||||
for module in DEPENDENCIES:
|
||||
g.insert_vertex(module)
|
||||
for module, deps in DEPENDENCIES.items():
|
||||
for dep in deps:
|
||||
g.connect(dep, module) # dep muss vor module gebaut werden
|
||||
|
||||
g.graph("BuildDependencies")
|
||||
|
||||
# --- b) DFS ausführen --------------------------------------------------------
|
||||
enter_map, leave_map, pred_map = g.dfs()
|
||||
|
||||
print("Zeitmarken (DFS):")
|
||||
for v in sorted(enter_map, key=lambda v: enter_map[v]):
|
||||
print(f" {v.value:12s} begin={enter_map[v]:2d} end={leave_map[v]:2d}")
|
||||
print()
|
||||
|
||||
# --- c) Topologische Sortierung ----------------------------------------------
|
||||
sorted_vertices = sorted(leave_map, key=lambda v: leave_map[v], reverse=True)
|
||||
reihenfolge = [v.value for v in sorted_vertices]
|
||||
print("Topologische Reihenfolge (Build-Reihenfolge):")
|
||||
print(" " + " -> ".join(reihenfolge))
|
||||
print()
|
||||
|
||||
# Überprüfung: Für jede Abhängigkeit A->B muss A nach B in der Liste kommen.
|
||||
pos = {name: i for i, name in enumerate(reihenfolge)}
|
||||
ok = all(pos[dep] < pos[module]
|
||||
for module, deps in DEPENDENCIES.items()
|
||||
for dep in deps)
|
||||
print(f"Alle Abhängigkeiten eingehalten: {ok}")
|
||||
print()
|
||||
|
||||
# --- d) Komplexität ----------------------------------------------------------
|
||||
v_count = len(list(g.all_vertices()))
|
||||
e_count = sum(len(g.get_adjacent_vertices(v.value)) for v in g.all_vertices())
|
||||
print(f"|V| = {v_count}, |E| = {e_count}")
|
||||
# Jeder Knoten wird genau einmal grau (begin) und einmal schwarz (end) => O(|V|)
|
||||
# Jede Kante wird beim ersten Besuch des Ausgangsknotens genau einmal betrachtet => O(|E|)
|
||||
# Zusammen: O(|V| + |E|)
|
||||
Loading…
x
Reference in New Issue
Block a user