Compare commits
4
Commits
50cf0b9b52
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
242b7fdc34 | ||
|
|
00466b6ad7 | ||
|
|
4bad896096 | ||
|
|
82a6d35942 |
No files matched your search
@@ -0,0 +1,52 @@
|
|||||||
|
from SoSe24.algodat.foundation import AlgoDatArray
|
||||||
|
|
||||||
|
|
||||||
|
class AlgoDatHeap():
|
||||||
|
|
||||||
|
def __init__(self, values: AlgoDatArray):
|
||||||
|
self.heap = values
|
||||||
|
self.size = len(values)
|
||||||
|
|
||||||
|
def left_child(self, i):
|
||||||
|
return 2*i + 1
|
||||||
|
|
||||||
|
def right_child(self, i):
|
||||||
|
return 2*i + 2
|
||||||
|
|
||||||
|
def parent(self, i):
|
||||||
|
return (i-1)//2
|
||||||
|
|
||||||
|
def max_heapify(self, i):
|
||||||
|
l = self.left_child(i)
|
||||||
|
r = self.right_child(i)
|
||||||
|
largest = i
|
||||||
|
if l <= self.size and self.heap[l-1] > self.heap[i-1]:
|
||||||
|
largest = l
|
||||||
|
if r <= self.size and self.heap[r-1] > self.heap[largest-1]:
|
||||||
|
largest = r
|
||||||
|
if largest != i:
|
||||||
|
self.heap[i-1], self.heap[largest-1] = self.heap[largest-1], self.heap[i-1]
|
||||||
|
self.max_heapify(largest)
|
||||||
|
|
||||||
|
def min_heapify(self, i):
|
||||||
|
l = self.left_child(i)
|
||||||
|
r = self.right_child(i)
|
||||||
|
smallest = i
|
||||||
|
if l <= self.size and self.heap[l-1] < self.heap[i-1]:
|
||||||
|
smallest = l
|
||||||
|
if r <= self.size and self.heap[r-1] < self.heap[smallest-1]:
|
||||||
|
smallest = r
|
||||||
|
if smallest != i:
|
||||||
|
self.heap[i-1], self.heap[smallest-1] = self.heap[smallest-1], self.heap[i-1]
|
||||||
|
self.min_heapify(smallest)
|
||||||
|
|
||||||
|
def build_max_heap(self):
|
||||||
|
for i in range(self.size//2, 0, -1):
|
||||||
|
self.max_heapify(i)
|
||||||
|
|
||||||
|
def build_min_heap(self):
|
||||||
|
for i in range(self.size//2, 0, -1):
|
||||||
|
self.min_heapify(i)
|
||||||
|
|
||||||
|
def as_list(self):
|
||||||
|
return [self.heap[i].value for i in range(self.size)]
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
import math
|
||||||
|
from typing import Callable
|
||||||
|
import re
|
||||||
|
from graph import Graph, AdjacencyListGraph, AdjacencyMatrixGraph, NodeColor, Vertex
|
||||||
|
import heapq
|
||||||
|
|
||||||
|
def a_star(self, start_name: str, end_name: str, heuristic: Callable[[Vertex], float]):
|
||||||
|
color_map = {} # maps vertices to their color
|
||||||
|
distance_map = {} # maps vertices to their distance from the start vertex
|
||||||
|
predecessor_map = {} # maps vertices to their predecessor in the traversal tree
|
||||||
|
|
||||||
|
def cost(vertex: Vertex) -> float:
|
||||||
|
"""Compute the cost of the path to the given vertex."""
|
||||||
|
if distance_map[vertex] is None:
|
||||||
|
return math.inf
|
||||||
|
return distance_map[vertex] + heuristic(vertex)
|
||||||
|
|
||||||
|
Vertex.__lt__ = lambda self, other: cost(self) < cost(other)
|
||||||
|
|
||||||
|
# Initialize the maps
|
||||||
|
for vertex in self.all_vertices():
|
||||||
|
color_map[vertex] = NodeColor.WHITE
|
||||||
|
distance_map[vertex] = None
|
||||||
|
predecessor_map[vertex] = None
|
||||||
|
|
||||||
|
# Start at the given vertex
|
||||||
|
start_node = self.get_vertex(start_name)
|
||||||
|
color_map[start_node] = NodeColor.GRAY
|
||||||
|
distance_map[start_node] = 0
|
||||||
|
|
||||||
|
# Initialize the queue with the start vertex
|
||||||
|
queue = [] # Use a list instead of a deque, because we need to sort it with
|
||||||
|
heapq.heappush(queue, start_node)
|
||||||
|
|
||||||
|
# Process the queue
|
||||||
|
while len(queue) > 0:
|
||||||
|
vertex = heapq.heappop(queue)
|
||||||
|
if color_map[vertex] == NodeColor.BLACK:
|
||||||
|
# Skip already processed vertices (possibly with a higher cost)
|
||||||
|
continue
|
||||||
|
if vertex.value == end_name:
|
||||||
|
# Return the distance and predecessor maps
|
||||||
|
return distance_map, predecessor_map
|
||||||
|
for dest, weight in self.get_adjacent_vertices_with_weight(vertex.value):
|
||||||
|
if color_map[dest] == NodeColor.BLACK:
|
||||||
|
continue
|
||||||
|
f = distance_map[vertex] + weight + heuristic(dest)
|
||||||
|
if color_map[dest] == NodeColor.GRAY and f > cost(dest):
|
||||||
|
continue
|
||||||
|
predecessor_map[dest] = vertex
|
||||||
|
distance_map[dest] = distance_map[vertex] + weight
|
||||||
|
heapq.heappush(queue, dest)
|
||||||
|
if color_map[dest] == NodeColor.WHITE:
|
||||||
|
color_map[dest] = NodeColor.GRAY
|
||||||
|
color_map[vertex] = NodeColor.BLACK
|
||||||
|
|
||||||
|
# Return the distance and predecessor maps if no path was found
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
|
||||||
|
# Add the a_star method to the Graph classes
|
||||||
|
AdjacencyListGraph.a_star = a_star
|
||||||
|
AdjacencyMatrixGraph.a_star = a_star
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
def read_labyrinth_into_graph(graph: Graph, filename: str):
|
||||||
|
"""Read a labyrinth from a file into a graph. The file format is a grid of characters:"""
|
||||||
|
start = None
|
||||||
|
end = None
|
||||||
|
with open(filename, "r") as file:
|
||||||
|
nodes = []
|
||||||
|
lines = file.readlines()
|
||||||
|
for y, line in enumerate(lines):
|
||||||
|
for x, char in enumerate(line):
|
||||||
|
if char in ' AS':
|
||||||
|
name = pos_to_nodename((x, y))
|
||||||
|
graph.insert_vertex(name)
|
||||||
|
nodes.append((x, y))
|
||||||
|
if char == 'A':
|
||||||
|
end = (x, y)
|
||||||
|
if char == 'S':
|
||||||
|
start = (x, y)
|
||||||
|
for x, y in nodes:
|
||||||
|
name1 = f"x{x}y{y}"
|
||||||
|
for neighbor in [(x - 1, y), (x, y - 1), (x, y + 1), (x + 1, y)]:
|
||||||
|
if neighbor in nodes:
|
||||||
|
name_neighbor = pos_to_nodename(neighbor)
|
||||||
|
graph.connect(name1, name_neighbor, 1)
|
||||||
|
return start, end, lines
|
||||||
|
|
||||||
|
|
||||||
|
def nodename_to_pos(nodename):
|
||||||
|
"""Convert a node name to a position (x, y)."""
|
||||||
|
m = re.match(r"(^x(\d*)y(\d*))", nodename)
|
||||||
|
if m:
|
||||||
|
return (int(m.group(2)), int(m.group(3)))
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def pos_to_nodename(pos):
|
||||||
|
"""Convert a position (x, y) to a node name."""
|
||||||
|
x, y = pos
|
||||||
|
return f"x{x}y{y}"
|
||||||
|
|
||||||
|
|
||||||
|
def get_heuristic(end) -> Callable[[Vertex], float]:
|
||||||
|
"""Return a heuristic function for the given end position."""
|
||||||
|
def heuristic(v: Vertex) -> float:
|
||||||
|
x, y = nodename_to_pos(v.value)
|
||||||
|
x1, y1 = end
|
||||||
|
# Euclidean distance
|
||||||
|
return math.sqrt(abs(x - x1)**2 + abs(y - y1)**2)
|
||||||
|
|
||||||
|
return heuristic
|
||||||
|
|
||||||
|
def update_lines(lines, distance_map, path):
|
||||||
|
"""Update the lines with the path found by the A* algorithm."""
|
||||||
|
def replace_at(x, y, replacement):
|
||||||
|
if lines[y][x] not in " .":
|
||||||
|
return
|
||||||
|
lines[y] = lines[y][:x] + replacement + lines[y][x+1:]
|
||||||
|
|
||||||
|
for node in distance_map.keys():
|
||||||
|
if distance_map[node] is not None:
|
||||||
|
x, y = nodename_to_pos(node.value)
|
||||||
|
replace_at(x, y, ".")
|
||||||
|
for node in path:
|
||||||
|
x, y = nodename_to_pos(node)
|
||||||
|
replace_at(x, y, "*")
|
||||||
|
return lines
|
||||||
|
|
||||||
|
graph = AdjacencyListGraph()
|
||||||
|
#graph = AdjacencyMatrixGraph()
|
||||||
|
start, end, lines = read_labyrinth_into_graph(graph, "../../labyrinth.txt")
|
||||||
|
distance_map, predecessor_map = graph.a_star(pos_to_nodename(start), pos_to_nodename(end), get_heuristic(end))
|
||||||
|
endname = pos_to_nodename(end)
|
||||||
|
lines = update_lines(lines, distance_map, graph.path(endname, predecessor_map))
|
||||||
|
for line in lines:
|
||||||
|
print(line, end="")
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class DisjointValue():
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = value
|
||||||
|
self.parent = None
|
||||||
|
|
||||||
|
def canonical(self):
|
||||||
|
if self.parent:
|
||||||
|
return self.parent.canonical()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def same_set(self, other):
|
||||||
|
return self.canonical() == other.canonical()
|
||||||
|
|
||||||
|
def union(self, other):
|
||||||
|
self.canonical().parent = other.canonical()
|
||||||
@@ -16,12 +16,15 @@ class Vertex:
|
|||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self.value)
|
||||||
|
|
||||||
class Graph:
|
class Graph:
|
||||||
"""A graph."""
|
"""A graph."""
|
||||||
def insert_vertex(self, name: str):
|
def insert_vertex(self, name: str):
|
||||||
raise NotImplementedError("Please implement this method in subclass")
|
raise NotImplementedError("Please implement this method in subclass")
|
||||||
|
|
||||||
def connect(self, name1: str, name2: str):
|
def connect(self, name1: str, name2: str, weight: float = 1):
|
||||||
raise NotImplementedError("Please implement this method in subclass")
|
raise NotImplementedError("Please implement this method in subclass")
|
||||||
|
|
||||||
def all_vertices(self) -> List[Vertex]:
|
def all_vertices(self) -> List[Vertex]:
|
||||||
@@ -33,6 +36,12 @@ class Graph:
|
|||||||
def get_adjacent_vertices(self, name: str) -> List[Vertex]:
|
def get_adjacent_vertices(self, name: str) -> List[Vertex]:
|
||||||
raise NotImplementedError("Please implement this method in subclass")
|
raise NotImplementedError("Please implement this method in subclass")
|
||||||
|
|
||||||
|
def get_adjacent_vertices_with_weight(self, name: str) -> List[tuple[Vertex, float]]:
|
||||||
|
raise NotImplementedError("Please implement this method in subclass")
|
||||||
|
|
||||||
|
def all_edges(self) -> List[tuple[str, str, float]]:
|
||||||
|
raise NotImplementedError("Please implement this method in subclass")
|
||||||
|
|
||||||
def bfs(self, start_name: str):
|
def bfs(self, start_name: str):
|
||||||
"""
|
"""
|
||||||
Perform a breadth-first search starting at the given vertex.
|
Perform a breadth-first search starting at the given vertex.
|
||||||
@@ -74,6 +83,7 @@ class Graph:
|
|||||||
# Return the distance and predecessor maps
|
# Return the distance and predecessor maps
|
||||||
return distance_map, predecessor_map
|
return distance_map, predecessor_map
|
||||||
|
|
||||||
|
|
||||||
def path(self, destination, map):
|
def path(self, destination, map):
|
||||||
"""
|
"""
|
||||||
Compute the path from the start vertex to the given destination vertex.
|
Compute the path from the start vertex to the given destination vertex.
|
||||||
@@ -100,10 +110,10 @@ class AdjacencyListGraph(Graph):
|
|||||||
if name not in self.adjacency_map:
|
if name not in self.adjacency_map:
|
||||||
self.adjacency_map[name] = []
|
self.adjacency_map[name] = []
|
||||||
|
|
||||||
def connect(self, name1: str, name2: str):
|
def connect(self, name1: str, name2: str, weight: float = 1):
|
||||||
adjacency_list = self.adjacency_map[name1]
|
adjacency_list = self.adjacency_map[name1]
|
||||||
dest = self.vertex_map[name2]
|
dest = self.vertex_map[name2]
|
||||||
adjacency_list.append(dest)
|
adjacency_list.append((dest, weight))
|
||||||
|
|
||||||
def all_vertices(self) -> List[Vertex]:
|
def all_vertices(self) -> List[Vertex]:
|
||||||
return list(self.vertex_map.values())
|
return list(self.vertex_map.values())
|
||||||
@@ -112,7 +122,19 @@ class AdjacencyListGraph(Graph):
|
|||||||
return self.vertex_map[name]
|
return self.vertex_map[name]
|
||||||
|
|
||||||
def get_adjacent_vertices(self, name: str) -> List[Vertex]:
|
def get_adjacent_vertices(self, name: str) -> List[Vertex]:
|
||||||
|
return list(map(lambda x: x[0], self.adjacency_map[name]))
|
||||||
|
|
||||||
|
def get_adjacent_vertices_with_weight(self, name: str) -> List[tuple[Vertex, float]]:
|
||||||
return self.adjacency_map[name]
|
return self.adjacency_map[name]
|
||||||
|
def all_edges(self) -> List[tuple[str, str, float]]:
|
||||||
|
result = []
|
||||||
|
for name in self.adjacency_map:
|
||||||
|
for (dest, weight) in self.adjacency_map[name]:
|
||||||
|
result.append((name, dest.value, weight))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AdjacencyMatrixGraph(Graph):
|
class AdjacencyMatrixGraph(Graph):
|
||||||
"""A graph implemented as an adjacency matrix."""
|
"""A graph implemented as an adjacency matrix."""
|
||||||
@@ -126,13 +148,13 @@ class AdjacencyMatrixGraph(Graph):
|
|||||||
self.index_map[name] = len(self.vertex_list)
|
self.index_map[name] = len(self.vertex_list)
|
||||||
self.vertex_list.append(Vertex(name))
|
self.vertex_list.append(Vertex(name))
|
||||||
for row in self.adjacency_matrix: # add a new column to each row
|
for row in self.adjacency_matrix: # add a new column to each row
|
||||||
row.append(0)
|
row.append(None)
|
||||||
self.adjacency_matrix.append([0] * len(self.vertex_list)) # add a new row
|
self.adjacency_matrix.append([None] * len(self.vertex_list)) # add a new row
|
||||||
|
|
||||||
def connect(self, name1: str, name2: str):
|
def connect(self, name1: str, name2: str, weight: float = 1):
|
||||||
index1 = self.index_map[name1]
|
index1 = self.index_map[name1]
|
||||||
index2 = self.index_map[name2]
|
index2 = self.index_map[name2]
|
||||||
self.adjacency_matrix[index1][index2] = 1
|
self.adjacency_matrix[index1][index2] = weight
|
||||||
|
|
||||||
def all_vertices(self) -> List[Vertex]:
|
def all_vertices(self) -> List[Vertex]:
|
||||||
return self.vertex_list
|
return self.vertex_list
|
||||||
@@ -145,11 +167,33 @@ class AdjacencyMatrixGraph(Graph):
|
|||||||
index = self.index_map[name]
|
index = self.index_map[name]
|
||||||
result = []
|
result = []
|
||||||
for i in range(len(self.vertex_list)):
|
for i in range(len(self.vertex_list)):
|
||||||
if self.adjacency_matrix[index][i] == 1:
|
if self.adjacency_matrix[index][i] is not None:
|
||||||
name = self.vertex_list[i].value
|
name = self.vertex_list[i].value
|
||||||
result.append(self.get_vertex(name))
|
result.append(self.get_vertex(name))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def get_adjacent_vertices_with_weight(self, name: str) -> List[tuple[Vertex, float]]:
|
||||||
|
index = self.index_map[name]
|
||||||
|
result = []
|
||||||
|
for i in range(len(self.vertex_list)):
|
||||||
|
if self.adjacency_matrix[index][i] is not None:
|
||||||
|
name = self.vertex_list[i].value
|
||||||
|
result.append((self.get_vertex(name), self.adjacency_matrix[index][i]))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def all_edges(self) -> List[tuple[str, str, float]]:
|
||||||
|
result = []
|
||||||
|
for i in range(len(self.vertex_list)):
|
||||||
|
for j in range(len(self.vertex_list)):
|
||||||
|
if self.adjacency_matrix[i][j] is not None:
|
||||||
|
result.append((self.vertex_list[i].value, self.vertex_list[j].value, self.adjacency_matrix[i][j]))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
def read_cave_into_graph(graph: Graph, filename: str):
|
def read_cave_into_graph(graph: Graph, filename: str):
|
||||||
"""Read a cave description from a file and insert it into the given graph."""
|
"""Read a cave description from a file and insert it into the given graph."""
|
||||||
with open(filename, "r") as file:
|
with open(filename, "r") as file:
|
||||||
@@ -169,7 +213,6 @@ def read_cave_into_graph(graph: Graph, filename: str):
|
|||||||
graph.connect(endnode, startnode)
|
graph.connect(endnode, startnode)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
graph = AdjacencyListGraph()
|
graph = AdjacencyListGraph()
|
||||||
#graph = AdjacencyMatrixGraph()
|
#graph = AdjacencyMatrixGraph()
|
||||||
read_cave_into_graph(graph, "../../hoehle.txt")
|
read_cave_into_graph(graph, "../../hoehle.txt")
|
||||||
@@ -179,3 +222,4 @@ if __name__ == "__main__":
|
|||||||
_, predecessor_map = graph.bfs('Schatzkammer')
|
_, predecessor_map = graph.bfs('Schatzkammer')
|
||||||
path = graph.path('Höhleneingang', predecessor_map)
|
path = graph.path('Höhleneingang', predecessor_map)
|
||||||
print(path)
|
print(path)
|
||||||
|
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
import math
|
||||||
|
import re
|
||||||
|
|
||||||
|
from SoSe24.lec06_graph.disjoint import DisjointValue
|
||||||
|
from graph import Graph, AdjacencyListGraph, AdjacencyMatrixGraph, Vertex
|
||||||
|
import heapq
|
||||||
|
|
||||||
|
|
||||||
|
def mst_prim(self, start_name: str = None):
|
||||||
|
""" Compute the minimum spanning tree of the graph using Prim's algorithm. """
|
||||||
|
|
||||||
|
distance_map = {} # maps vertices to their current distance from the spanning tree
|
||||||
|
parent_map = {} # maps vertices to their predecessor in the spanning tree
|
||||||
|
|
||||||
|
Vertex.__lt__ = lambda self, other: distance_map[self] < distance_map[other]
|
||||||
|
|
||||||
|
queue = []
|
||||||
|
|
||||||
|
if start_name is None:
|
||||||
|
start_name = self.all_vertices()[0].value;
|
||||||
|
|
||||||
|
# Initialize the maps
|
||||||
|
for vertex in self.all_vertices():
|
||||||
|
distance_map[vertex] = 0 if vertex.value == start_name else math.inf
|
||||||
|
parent_map[vertex] = None
|
||||||
|
queue.append(vertex)
|
||||||
|
|
||||||
|
heapq.heapify(queue) # Convert the list into a heap
|
||||||
|
|
||||||
|
# Process the queue
|
||||||
|
cost = 0 # The cost of the minimum spanning tree
|
||||||
|
while len(queue) > 0:
|
||||||
|
vertex = heapq.heappop(queue)
|
||||||
|
cost += distance_map[vertex] # Add the cost of the edge to the minimum spanning tree
|
||||||
|
for (dest, w) in self.get_adjacent_vertices_with_weight(vertex.value):
|
||||||
|
if dest in queue and distance_map[dest] > w:
|
||||||
|
# Update the distance and parent maps
|
||||||
|
queue.remove(dest)
|
||||||
|
distance_map[dest] = w
|
||||||
|
parent_map[dest] = vertex
|
||||||
|
queue.append(dest) # Add the vertex back to the queue
|
||||||
|
heapq.heapify(queue) # Re-heapify the queue
|
||||||
|
|
||||||
|
# Return the distance and predecessor maps
|
||||||
|
return parent_map, cost
|
||||||
|
|
||||||
|
|
||||||
|
def mst_kruskal(self, start_name: str = None):
|
||||||
|
""" Compute the minimum spanning tree of the graph using Kruskal's algorithm. """
|
||||||
|
|
||||||
|
cost = 0
|
||||||
|
result = []
|
||||||
|
edges = self.all_edges()
|
||||||
|
|
||||||
|
# Create a disjoint set for each vertex
|
||||||
|
vertex_map = {v.value: DisjointValue(v) for v in self.all_vertices()}
|
||||||
|
|
||||||
|
# Sort the edges by weight
|
||||||
|
edges.sort(key=lambda edge: edge[2])
|
||||||
|
|
||||||
|
# Process the edges
|
||||||
|
for edge in edges:
|
||||||
|
start_name, end_name, weight = edge
|
||||||
|
# Check if the edge creates a cycle
|
||||||
|
if not vertex_map[start_name].same_set(vertex_map[end_name]):
|
||||||
|
result.append(edge)
|
||||||
|
vertex_map[start_name].union(vertex_map[end_name])
|
||||||
|
cost += weight
|
||||||
|
|
||||||
|
return result, cost
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AdjacencyListGraph.mst_prim = mst_prim
|
||||||
|
AdjacencyMatrixGraph.mst_prim = mst_prim
|
||||||
|
|
||||||
|
AdjacencyListGraph.mst_kruskal = mst_kruskal
|
||||||
|
AdjacencyMatrixGraph.mst_kruskal = mst_kruskal
|
||||||
|
|
||||||
|
|
||||||
|
def read_elektro_into_graph(graph: Graph, filename: str):
|
||||||
|
pattern = re.compile(r'"([^"]+)";"([^"]+)";(\d+)')
|
||||||
|
with (open(filename, "r") as file):
|
||||||
|
for line in file:
|
||||||
|
m = pattern.match(line)
|
||||||
|
if m:
|
||||||
|
start_name = m.group(1)
|
||||||
|
end_name = m.group(2)
|
||||||
|
cost = int(m.group(3))
|
||||||
|
graph.insert_vertex(start_name)
|
||||||
|
graph.insert_vertex(end_name)
|
||||||
|
graph.connect(start_name, end_name, cost)
|
||||||
|
graph.connect(end_name, start_name, cost)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
graph = AdjacencyMatrixGraph()
|
||||||
|
read_elektro_into_graph(graph, "../../elektro.txt")
|
||||||
|
|
||||||
|
parents, cost = graph.mst_prim()
|
||||||
|
print(f"Kosten nach Prim: {cost}")
|
||||||
|
for node, parent in parents.items():
|
||||||
|
if parent is not None:
|
||||||
|
print(f"{node} - {parent}")
|
||||||
|
|
||||||
|
edges, cost = graph.mst_kruskal()
|
||||||
|
print(f"Kosten nach Kruskal: {cost}")
|
||||||
|
for start_name, end_name, _ in edges:
|
||||||
|
print(f"{start_name} - {end_name}")
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
"Höhleneingang";"Ost/West-Passage";5
|
||||||
|
"Höhleneingang";"Nord/Süd-Passage";3
|
||||||
|
"Nord/Süd-Passage";"Nebelraum";7
|
||||||
|
"Steiniger Pfad";"Ost/West-Passage";2
|
||||||
|
"Ost/West-Passage";"Schwefelgewölbe";4
|
||||||
|
"Schwefelgewölbe";"Steiniger Pfad";1
|
||||||
|
"Schatzkammer";"Nebelraum";2
|
||||||
|
"Steiniger Pfad";"Schatzkammer";6
|
||||||
Reference in new issue
Block a user