90 lines
2.1 KiB
Python
90 lines
2.1 KiB
Python
|
from dataclasses import dataclass
|
||
|
from typing import List
|
||
|
|
||
|
|
||
|
@dataclass
|
||
|
class Edge:
|
||
|
weight: int
|
||
|
source_id: int
|
||
|
target_id: int
|
||
|
|
||
|
|
||
|
@dataclass
|
||
|
class Vertex:
|
||
|
id: int
|
||
|
edges: List[Edge]
|
||
|
|
||
|
|
||
|
def load_matrix(filename):
|
||
|
def line_to_row(line):
|
||
|
r = []
|
||
|
for field in line.strip().split(","):
|
||
|
if field == "-":
|
||
|
r.append(0)
|
||
|
else:
|
||
|
r.append(int(field))
|
||
|
return r
|
||
|
|
||
|
with open(filename, "r") as f:
|
||
|
m = [line_to_row(l) for l in f]
|
||
|
return m
|
||
|
|
||
|
|
||
|
def matrix_to_graph(matrix):
|
||
|
n_nodes = len(matrix)
|
||
|
graph = []
|
||
|
for row_index in range(n_nodes):
|
||
|
|
||
|
edges = []
|
||
|
for col_index in range(n_nodes):
|
||
|
weight = matrix[row_index][col_index]
|
||
|
if weight != 0:
|
||
|
edges.append(Edge(weight, row_index, col_index))
|
||
|
graph.append(Vertex(row_index, edges))
|
||
|
return graph
|
||
|
|
||
|
|
||
|
def total_weight(graph):
|
||
|
total_weight = 0
|
||
|
for vertex in graph:
|
||
|
for edge in vertex.edges:
|
||
|
total_weight += edge.weight
|
||
|
total_weight //= 2
|
||
|
return total_weight
|
||
|
|
||
|
|
||
|
def prims_algo(graph):
|
||
|
""" Takes a graph and returns the edges that for a minimum spanning tree
|
||
|
for that graph. """
|
||
|
visited_id = set([0])
|
||
|
min_edges = []
|
||
|
while len(visited_id) != len(graph):
|
||
|
min_edge = None
|
||
|
for vertex_id in visited_id:
|
||
|
vertex = graph[vertex_id]
|
||
|
for edge in vertex.edges:
|
||
|
if edge.target_id in visited_id:
|
||
|
pass
|
||
|
elif min_edge is None:
|
||
|
min_edge = edge
|
||
|
elif edge.weight < min_edge.weight:
|
||
|
min_edge = edge
|
||
|
visited_id.add(min_edge.target_id)
|
||
|
min_edges.append(min_edge)
|
||
|
return min_edges
|
||
|
|
||
|
|
||
|
def euler_107():
|
||
|
m = load_matrix("../txt/e107.txt")
|
||
|
g = matrix_to_graph(m)
|
||
|
weight = total_weight(g)
|
||
|
new_weight = sum([e.weight for e in prims_algo(g)])
|
||
|
return weight - new_weight
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
solution = euler_107()
|
||
|
print("e107.py: " + str(solution))
|
||
|
assert(solution == 259679)
|
||
|
|