62 lines
1.4 KiB
Python
62 lines
1.4 KiB
Python
from collections import deque, defaultdict
|
|
from itertools import permutations
|
|
from lib import Grid2D, INF
|
|
|
|
|
|
def shortest_path(grid, start, end):
|
|
seen = set()
|
|
open = deque([(start, 0)])
|
|
|
|
while open:
|
|
current, steps = open.popleft()
|
|
if current in seen:
|
|
continue
|
|
seen.add(current)
|
|
if current == end:
|
|
return steps
|
|
for nb in grid.neighbors_ort(current):
|
|
if grid[nb] == "#":
|
|
continue
|
|
open.append((nb, steps + 1))
|
|
return None
|
|
|
|
|
|
def solve(data, part_2=False):
|
|
g = Grid2D(data)
|
|
# g.print()
|
|
start = g.find("0")[0]
|
|
points = g.find_not("#.")
|
|
|
|
shortest = defaultdict(defaultdict)
|
|
for i in range(len(points)):
|
|
for j in range(i + 1, len(points)):
|
|
a, b = points[i], points[j]
|
|
s = shortest_path(g, a, b)
|
|
assert s is not None
|
|
shortest[a][b] = s
|
|
shortest[b][a] = s
|
|
|
|
# Brute force all combinations.
|
|
points.remove(start)
|
|
dmin = INF
|
|
for p in permutations(points):
|
|
d = 0
|
|
d += shortest[start][p[0]]
|
|
for i in range(len(p) - 1):
|
|
d += shortest[p[i]][p[i + 1]]
|
|
if part_2:
|
|
d += shortest[p[-1]][start]
|
|
dmin = min(d, dmin)
|
|
print(dmin)
|
|
return
|
|
|
|
|
|
def main():
|
|
data = open(0).read().strip()
|
|
solve(data)
|
|
solve(data, True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|