There is no snow, you decide to investigate the spot directly beneath the waterfall.
You find a buch of lean, mean, snow making machines connected with wires.
They don’t seem to be working, only displaying an error code on a screen.
You call the technical snow-machine support and they tell you it’s a power overload error.
That means there are too many machines connected and you should disconnect some.
You need to disconnect at least half of the equipment.
There is not a lot of time left as it is almost Christmas, and you can only disconnect 3 wires.
Today’s input is a wiring diagram that shows how the machines are connected.
An example input looks like this:
Each line shows the name of a machine, a colon :, and a list of the machines it is connected to that’s separated by spaces.
Parsing
I represented the network of machines and cables as a graph in the form of a map.
A key in that map is the name of a machine, the value is a list of machines it is connected to.
Part 1
Disconnect 3 wires to split the network of machines into 2 groups.
Count the amount of machines in each group.
The question asks what number you get if you multiply the amount of machines in those 2 groups.
In pseudo/skeleton-code:
Option 1: count ALL the paths!
Find the path between every pair of nodes.
We can assume the 3 most used edges (cables) are the 3 separating the 2 groups of nodes.
The reason for this is that every node in one half will have to use one of those 3 edges to reach any node in the other half.
That magic number 3 is given in the question.
I used BFS to find the path from one node to all other nodes in one loop.
Incrementing a count for each specific edge that was used.
Helpers
The function that counts how many times each edge was used.
The order of the nodes does not matter, going from abc to xyz uses the same edge as going from xyz to abc.
That is why before incrementing the edge count, I sort those 2 strings.
In this version of the same function, I eliminated the nested loop that does the backtracking.
I did not increment the counts in edges for a path between all possible pairs of nodes.
Instead, I incremented the count for an edge as the BFS was running.
This means some edges that are used in a buch of paths will only be counted once.
Because one of the 3 separating edges has to be used in every path that goes from one half to the other,
the 3 most used edges will still be the separating edges.
A helper that takes in the original graph,
computes the edge usage counts using the previous helper,
then sorts those counts and returns the 3 most used edges:
Finally a helper that counts the amount of nodes that are reachable when starting from a given node:
Now it’s time to put these 3 helpers together into the form of the skeletoncode I started with!
Code
Option 2: deleting until victorious
For this solution, pick 2 nodes and assume they are in separate halves.
If they are not, that’s not a problem because eventually the code will know they’re not and move on until it finds a pair that is.
This solution finds a path from the starting node to the ending node.
It has to have travelled across one of those 3 separating edges.
Then it deletes all edges along that path.
It will delete one of the 3 separating edges, leaving 2.
The next path from that same starting node to the same ending node now has to travel across one of those 2 edges.
The third time, all 3 separating nodes have been deleted, separating the graph in 2 halves.
The other edges that got deleted during this procedure have no impact, all nodes in a half will still be reachable.
Because from the problem statement we know it will be impossible to sever the graph with any other 3 cuts.
This means all nodes in a half are still reachable when starting from a random node in that half.
Helpers
A helper function that finds a route between 2 nodes, and deletes all edges it used.
It first finds a path while keeping track of the route it took, then it backtracks along that route while severing the edges it used:
The reachable_nodes helper from the previous solution is reused with some slight changes.
It now returns nothing if the graph wasn’t cut in 2.
In Rust, this is done with the Option type.
The function either returns a count of a half, or it returns nothing:
These 2 helpers are then put together in the final code.
It checks every combination of 2 nodes until it finds 2 that are in separate halves.
Code
Part 2
This part is very secret.
It started snowing, have a great year, and see you next year for more Advent of Come!