from lib import * from random import choice from collections import deque # def plot(graph): # import networkx as nx # import matplotlib # import matplotlib.pyplot as plt # G = nx.Graph() # for node, connected_nodes in graph.items(): # for connected_node in connected_nodes: # G.add_edge(node, connected_node) # # pos = nx.spring_layout(G, k=2.0, iterations=20) # Adjust k as needed # pos = nx.shell_layout(G) # nx.draw(G, with_labels=True, node_color='lightblue', edge_color='gray', node_size=2000, font_size=15, font_weight='bold') # matplotlib.use('qtagg') # plt.show() def solve(input: Input): graph = {} edges = {} for line in input.lines(): src, dsts = line.split(":") dsts = dsts.strip().split(" ") if not src in graph: graph[src] = [] for dst in dsts: graph[src].append(dst) if not dst in graph: graph[dst] = [] graph[dst].append(src) edge = tuple(sorted([src, dst])) edges[edge] = 0 for _ in range(100): first_node = choice(list(graph.keys())) seen = set([first_node]) visit = deque([first_node]) while visit: node = visit.popleft() for nb in graph[node]: if not nb in seen: seen.add(nb) visit.append(nb) edge = tuple(sorted([node, nb])) edges[edge] += 1 # Orignally, I used `plot(graph)` to visually find the nodes that have to # be removed. I then came up with this heuristic approach. The idea is that # we have to cross one of the three nodes when we do a breadth first # search. By repeatedly doing that we can identify the "bridges" as the # three edges that are used the most often. most_visited = sorted(edges.items(), key=lambda t: t[1], reverse=True)[:3] # to_remove = (("plt", "mgb"), ("jxm", "qns"), ("dbt", "tjd")) # found visually # for node, count in most_visited: # print(node, count) # should print the same as `to_remove` for (a, b), _ in most_visited: graph[a].remove(b) graph[b].remove(a) to_visit = [choice(list(graph.keys()))] seen = set(to_visit) while to_visit: node = to_visit.pop() for nb in graph[node]: if not nb in seen: seen.add(nb) to_visit.append(nb) return len(seen) * (len(graph) - len(seen)) def main(): DAY_INPUT = "i25.txt" print("Solution 1:", solve(Input(DAY_INPUT)), "(hands-free)") if __name__ == "__main__": main()