mirror of
https://github.com/cupcakearmy/advent-of-code.git
synced 2025-09-05 14:50:39 +00:00
2024
This commit is contained in:
10
2024/05/day_5_dag_reduced.svg
Normal file
10
2024/05/day_5_dag_reduced.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 10 KiB |
33
2024/05/day_5_dag_test.svg
Normal file
33
2024/05/day_5_dag_test.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 122 KiB |
20
2024/05/findings.md
Normal file
20
2024/05/findings.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Day 5
|
||||
|
||||
# Part 1
|
||||
|
||||
What a joy! First day where a bit of Computer Science might actually help.
|
||||
So to me this looks like a [DAG](https://en.wikipedia.org/wiki/Directed_acyclic_graph), since if there has to be an order, cycles cannot be allowed. Otherwise the problem could not be solved.
|
||||
|
||||
For not I just hope that it's one cohesive DAG, and not 2 or more. Technically there is a possibility that more than one, disjoined DAGs are defined by the rules. If this occurs, we'll see.
|
||||
|
||||

|
||||
|
||||
We can see that there in this case there is one "start" and one "end". In this case `97` is the start and `13` the end. Again, there might be more than one "start" or "end".
|
||||
|
||||
My idea is to precompile an order so that `97=0` and `13=7` so that we then just map the numbers to their ascending number and check if the array is already sorted. Why? My assumption is that you do the work upfront and then it's efficient to check for each input.
|
||||
|
||||
The start and ends are easy, what about the _middle_ nodes? We can do a so called transitive reduction, simplifying the graph. Basically, if we know that `97` needs to be before `61` and `13` and at the same time `61` needs to be before `13`, we can delete the `97` before `13` link, as it's already specified going over `61`. Basically we eliminate all the "shortcuts". This gives us a nice line in this case.
|
||||
|
||||

|
||||
|
||||
_no code has been written until now, this might go terribly wrong 💩_
|
95
2024/05/main.py
Normal file
95
2024/05/main.py
Normal file
@@ -0,0 +1,95 @@
|
||||
from typing import List, Union, Tuple, Set
|
||||
from dataclasses import dataclass
|
||||
import networkx as nx
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
@dataclass
|
||||
class Node:
|
||||
id: int
|
||||
links: List
|
||||
|
||||
|
||||
@dataclass
|
||||
class Manual:
|
||||
rules: Tuple[int]
|
||||
updates: Tuple[int]
|
||||
|
||||
def check_update(self, update: Tuple[int]) -> bool:
|
||||
cur = 0
|
||||
for n in update:
|
||||
if n not in self.order:
|
||||
continue
|
||||
m = self.order[n]
|
||||
if m < cur:
|
||||
return False
|
||||
cur = m
|
||||
return True
|
||||
|
||||
def check(self):
|
||||
total = 0
|
||||
for update in self.updates:
|
||||
valid = self.check_update(update)
|
||||
if valid:
|
||||
total += update[len(update) // 2]
|
||||
return total
|
||||
|
||||
def build_rules(self):
|
||||
unique: Set[int] = set()
|
||||
for rule in self.rules:
|
||||
unique.add(rule[0])
|
||||
unique.add(rule[1])
|
||||
nodes = {n: Node(id=n, links=[]) for n in unique}
|
||||
for start, end in self.rules:
|
||||
nodes[start].links.append(end)
|
||||
|
||||
# Test
|
||||
G = nx.DiGraph()
|
||||
for rule in self.rules:
|
||||
G.add_edge(*rule)
|
||||
print(G.number_of_nodes())
|
||||
|
||||
TR = nx.transitive_reduction(G)
|
||||
subax1 = plt.subplot(121)
|
||||
nx.draw(TR, with_labels=True, font_weight="bold")
|
||||
plt.show()
|
||||
|
||||
sorted = list(nx.topological_sort(G))
|
||||
print(sorted)
|
||||
|
||||
# Topological sorting
|
||||
# https://cs.stackexchange.com/a/29133
|
||||
order = {n: i for i, n in enumerate(sorted)}
|
||||
self.order = order
|
||||
|
||||
@staticmethod
|
||||
def parse(raw: str):
|
||||
rules_raw, updates_raw = raw.strip().split("\n\n")
|
||||
rules = [tuple((map(int, line.split("|")))) for line in rules_raw.splitlines()]
|
||||
updates = [
|
||||
tuple(map(int, line.split(","))) for line in updates_raw.splitlines()
|
||||
]
|
||||
return Manual(rules, updates)
|
||||
|
||||
|
||||
def solve(raw: str) -> int:
|
||||
# Part 1
|
||||
part1 = 0
|
||||
part2 = 0
|
||||
|
||||
m = Manual.parse(raw)
|
||||
m.build_rules()
|
||||
part1 = m.check()
|
||||
|
||||
return (part1, part2)
|
||||
|
||||
|
||||
# Test
|
||||
with open("./2024/05/test.txt", "r") as f:
|
||||
result = solve(f.read().strip())
|
||||
print(result)
|
||||
|
||||
# Input
|
||||
with open("./2024/05/input.txt", "r") as f:
|
||||
result = solve(f.read().strip())
|
||||
print(result)
|
Reference in New Issue
Block a user