2
votes
Day 11: Reactor
Today's problem description: https://adventofcode.com/2025/day/11
Please post your solutions in your own top-level comment. Here's a template you can copy-paste into your comment to format it nicely, with the code collapsed by default inside an expandable section with syntax highlighting (you can replace python with any of the "short names" listed in this page of supported languages):
<details>
<summary>Part 1</summary>
```python
Your code here.
```
</details>
Glad to have an easy day for a change! Just a simple recursive search with memoization (not needed for part 1, but it doesn't hurt). Part 2 is just the product of the solutions to three separate problems solved the same way as part 1. Would've finished this quicker if I hadn't wasted time writing a naive BFS solution that would take forever to finish executing, but oh well. I wonder what tomorrow will be like... this feels a bit like the calm before the storm.
Solution (Lily)
Computing the number of paths in a directed acyclic graph is a classical DP problem. I used the direct approach of visiting nodes in a lexicographical order, each time updating the value for its children. The lexicographical order ensures that when visiting a node, I've already visited all its parents and its value is not going to change.
For path 1, the value of each node is just the sum of its parents, initializing the starting node with 1.
For part 2, I used exactly the same approach, except that I'm using 4 values for each node, each corresponding to one type of path: paths going through neither dac nor fft, paths going through dac but not fft, paths going through fft but not dac, and paths going through both. For most nodes, their counters are directly propagated to their children. For dac and fft nodes, the none counter gets propagated to the dac and fft counters respectively and the fft and dac counters respectively get propagated to the both counter.
Boths are O(n) with n the number of nodes in the graph, so it's super quick to compute, even when using strings as key/values for the graph (and doing a ton of copies): 60μs for part 1 and 420μs for part 2.
Solution (Rust)
Much easier today. Of course, that didn't stop me from making the same mistakes as yesterday.
Copied my BFS code (that was several orders of magnitude too inefficient for yesterday's problem) from yesterday to solve part 1. Why didn't I reuse the DFS (that also was too inefficient for yesterday's problem)? Because the BFS code was prettier.
Get to Part 2 and realized I should have just started with DFS. Oh well. Easy enough to just rewrite a DFS. Luckily, DFS is actually the right tool for this job, and this worked as expected. My original plan was to use a "visited" check for visiting the fft and dac nodes, but that turned out to make caching much more complicated than I wanted.
Part 1&2 [Python]
I am going to hide this to avoid hinting to others, but was this intentional or a happy accident?
My input (and I assume everyone's) had no paths from
dac -> fftso the second set ended up being irrelevant anyway. Your code wouldn't work if there was even 1 path fromdac -> fft.It was intentional.
There could potentially be other loops that don't go through both fft and dac, but since my code spit out an answer instead of hanging forever, I (now) know that there are no loops. I did consider loop detection, but did not end up implementing it.
Seems like there was one standard way to do it. Tricky input for part 2. I was afraid of infinite loops but the input was convenient on that front.
C# today because I was doing it with a coworker.
Parts 1 and 2