Clean up day 25 and add explanation.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
|
Pipfile
|
||||||
__pycache__
|
__pycache__
|
||||||
*.txt
|
*.txt
|
||||||
|
|||||||
80
d25.py
80
d25.py
@@ -1,58 +1,23 @@
|
|||||||
from lib import *
|
from lib import *
|
||||||
|
|
||||||
|
|
||||||
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_non_hands_free(input: Input):
|
|
||||||
graph = {}
|
|
||||||
for line in input.lines():
|
|
||||||
source, targets = line.split(":")
|
|
||||||
targets = targets.strip()
|
|
||||||
targets = targets.split(" ")
|
|
||||||
|
|
||||||
for target in targets:
|
|
||||||
if not source in graph:
|
|
||||||
graph[source] = [target]
|
|
||||||
else:
|
|
||||||
graph[source].append(target)
|
|
||||||
if not target in graph:
|
|
||||||
graph[target] = [source]
|
|
||||||
else:
|
|
||||||
graph[target].append(source)
|
|
||||||
|
|
||||||
# plot(graph) # I used this to find the nodes that have to be removed.
|
|
||||||
to_remove = (("plt", "mgb"), ("jxm", "qns"), ("dbt", "tjd"))
|
|
||||||
for a, b in to_remove:
|
|
||||||
graph[a].remove(b)
|
|
||||||
graph[b].remove(a)
|
|
||||||
|
|
||||||
to_visit = ["plt"]
|
|
||||||
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))
|
|
||||||
|
|
||||||
from random import choice
|
from random import choice
|
||||||
from collections import deque
|
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):
|
def solve(input: Input):
|
||||||
graph = {}
|
graph = {}
|
||||||
edges = {}
|
edges = {}
|
||||||
@@ -73,7 +38,7 @@ def solve(input: Input):
|
|||||||
edge = tuple(sorted([src, dst]))
|
edge = tuple(sorted([src, dst]))
|
||||||
edges[edge] = 0
|
edges[edge] = 0
|
||||||
|
|
||||||
for i in range (1000):
|
for _ in range(100):
|
||||||
first_node = choice(list(graph.keys()))
|
first_node = choice(list(graph.keys()))
|
||||||
seen = set([first_node])
|
seen = set([first_node])
|
||||||
visit = deque([first_node])
|
visit = deque([first_node])
|
||||||
@@ -86,9 +51,16 @@ def solve(input: Input):
|
|||||||
edge = tuple(sorted([node, nb]))
|
edge = tuple(sorted([node, nb]))
|
||||||
edges[edge] += 1
|
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]
|
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:
|
# for node, count in most_visited:
|
||||||
# print(node, count)
|
# print(node, count) # should print the same as `to_remove`
|
||||||
|
|
||||||
for (a, b), _ in most_visited:
|
for (a, b), _ in most_visited:
|
||||||
graph[a].remove(b)
|
graph[a].remove(b)
|
||||||
@@ -108,10 +80,8 @@ def solve(input: Input):
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
DAY_INPUT = "i25.txt"
|
DAY_INPUT = "i25.txt"
|
||||||
print("Solution 1:", solve_non_hands_free(Input(DAY_INPUT)))
|
|
||||||
print("Solution 1:", solve(Input(DAY_INPUT)), "(hands-free)")
|
print("Solution 1:", solve(Input(DAY_INPUT)), "(hands-free)")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Reference in New Issue
Block a user