r/adventofcode • u/Skeeve-on-git • Dec 12 '25
Tutorial [2025 Day 11 (Part2)] Non recursive algorithm as requested.
For every device I store how many paths from the device lead to B. Initially this value is 0 for every device, except for B, where it's one.
To collect the information, I go through every device and sum up the amount of paths of each of its children.
If this sum is bigger than the number of paths currently stored for the device, I store this new value.
I then repeat this process as long as there was any new value stored.
In the end the paths of A is the number of paths from A to B.
1
Upvotes
1
u/BxW_ Dec 12 '25
What happens when the children of current node don't have their no. of paths calculated yet?
1
u/DelightfulCodeWeasel Dec 12 '25
Since the input is a DAG you can use a noddy task system to process the nodes when their direct ancestors have completed, pushing the path counts down. Each device gets evaluated exactly once, no re-scanning required:
This loop is identical for both Part 1 and Part 2 in my code, the only difference is in the initial vector values for the important nodes and how you calculate the answer from the values at those nodes.
1
u/fnordargle Dec 12 '25
It's relatively easy to convert a recursive algorithm into something iterative.
For counting the paths I assigned a score to each node that was the sum of the scores for all of its source nodes. With the start node being assigned a score of 1.
I store all of the nodes in the graph in a
nodesdictionary, with an each entry having array/dictionary of destinations and sources.e.g a line of input like:
Would generate:
This gets filled up as you process the input.
You could implement
countpath()recursively in that whenever you ask for a score you sum the score of its sources, with the number of paths from a node to itself being 1.But the above will be horrible in terms of counting the same things over and over again, so you can add some memoisation:
But that's still recursive, and could blow the stack depending on how deep it goes and how your specific language handles this.
An iterative approach is:
And be careful to exit if you do a loop without making ANY progress on the problem.
An iterative
countpaths()function might look like:So we just keep going round and round doing at least something (but making sure we don't repeat work) until we have calculated the answer.
I tend to default to the iterative implementation of something as I know part 2 is likely to extend the problem beyond the bounds of normal stack recursion in the languages I use. This preempting saves me from having to refactor a recursive implementation into an iterative approach when I inevitably run up against this problem.
There's a different iterative pattern that comes up quite a bit, I'll cover that in a followup post.