2015-12-09 - All in a Single Night
(original .ipynb)
Puzzle input is a description of routes between destinations and their costs. Part one requires you to find the shortest path that touches every destination exactly once. Part two requires you to find the longest path that touches every destination exactly once.
from collections import defaultdict
from math import inf
puzzle_input_str = open("./puzzle_input/day9.txt").read()
total_routes = 0
def parse_edge(edge_str):
tokens = edge_str.split(" ")
return (tokens[0], tokens[2], int(tokens[4]))
def shortest_path_from(src, nodes, routes, visited, cost, func=min):
if len(nodes) == 0:
return cost
return func(
shortest_path_from(neighbour, nodes.symmetric_difference({neighbour}), routes, visited.union({src}), cost + edge_cost, func)
for (neighbour, edge_cost)
in routes[src]
if not (neighbour in visited)
)
def part_one(input_str, func=min):
routes = defaultdict(list)
nodes = set()
for line in input_str.split("\n"):
src, dest, cost = parse_edge(line)
routes[src].append((dest, cost))
routes[dest].append((src, cost))
nodes.add(src)
nodes.add(dest)
return func(
shortest_path_from(src, nodes.symmetric_difference({src}), routes, {src}, 0, func)
for src
in nodes
)
test_input_str = """London to Dublin = 464
London to Belfast = 518
Dublin to Belfast = 141"""
assert 605 == part_one(test_input_str)
print("part one:", part_one(puzzle_input_str))
part one: 207
def part_two(input_str):
return part_one(input_str, max)
assert 982 == part_two(test_input_str)
print("part two:", part_two(puzzle_input_str))
part two: 804