Add 2023 solutions
This commit is contained in:
87
2023/d25.py
Normal file
87
2023/d25.py
Normal file
@@ -0,0 +1,87 @@
|
||||
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 = "d25.txt"
|
||||
print("Solution 1:", solve(Input(DAY_INPUT)), "(hands-free)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user