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()