Editorial for Google Code Jam '22 Round 2 Problem A - Spiraling Into Control
Submitting an official solution before solving the problem yourself is a bannable offence.
Test Sets 1 and 2
You may or may not have run across the old chestnut of a technical
interview question that asks you to number all of the cells of a grid in
a spiral pattern. In this problem, doing that is potentially helpful for
the first two test sets. However, the last test set can be (and must be)
solved without explicitly creating and numbering a spiral. (For a case with
To make a numbered spiral, we can create a grid and loop through it,
starting from the upper left cell, and making a 90 degree turn to the right
each time we encounter a grid boundary or an already-numbered cell. One
clean way to do this is to use an array of "directions":
For Test Set 1, we can exhaustively enumerate all legal paths, using our
spiral numbering to determine which moves are allowed. We can keep track of
the shortcuts taken in each possible path, and see whether any path finishes
in exactly
For Test Set 2, we can refine this idea to avoid explicitly considering all possible paths. For each cell in the grid, we create an array that can hold up to one path for every possible number of moves "so far". Then we proceed along the spiral in consecutive numerical order. For every cell we visit, for every path in that cell's array, we try to extend it into all legal neighboring cells.
For example, in a
And so we have a
dynamic programming
/ memoization
solution. Since there is at most one shortcut to take in each cell, we do
constant work per cell; since we are populating a table that is
Test Set 3
To be able to handle grids with
- Given a value of
, determine whether a path with exactly moves exists. - Find such a path.
- Given the coordinates of a grid cell, find its number in the spiral.
We can begin by observing that the following values of IMPOSSIBLE
:
. In this case, even if we move as directly as possible toward the center (taking only shortcuts), there are not enough moves to get there.- Odd
. We can see this via a "checkerboard argument". Imagine that the grid has a checkerboard pattern, with the upper left cell being black. Then the diagonal running from the upper left cell to the lower right cell is entirely black, and so the central cell is black. Now, each move is in an orthogonal (i.e., "compass") direction, so each move either takes us from a black cell to a red cell or vice versa. Therefore, to end on the central cell, which is black, we must make an even number of moves.
As it turns out, these are the only impossible cases! To see why, it
helps to think of the spiral as consisting of concentric square rings, with
"ring" 0 being just the central cell, ring 1 being the eight cells around
that, ring 2 being the sixteen cells around ring 1, and so on. For example,
the rings in the
3333333
3222223
3211123
3210123
3211123
3222223
3333333
In ring 1, there are three possible shortcuts: we can move into ring 0 from the top, right, or bottom, and this will save us 6, 4, or 2 moves, respectively, compared to just walking through all of ring 1 (and into ring 0) without taking a shortcut. But we can only take one of these shortcuts.
In ring 2 (and beyond), for simplicity, let's only consider taking shortcuts that are in the same row or column as the central cell. There are four such shortcuts, and they will save us 14, 12, 10, or 8 moves, respectively. Notice that if we take the 8-move shortcut from ring 2, for example, we cannot use any of the shortcuts in ring 1. However, if we take the 14-move shortcut from ring 2, we will still have access to all three shortcuts in ring 1.
Similarly, in ring 3, the shortcuts save us 22, 20, 18, or 16 moves, and if we take the first of these, we still have access to all four shortcuts in ring 2.
We can turn these observations into a constructive solution for any even
- If we want to save between 2 and 22 moves, we take the specific shortcut with that savings.
- If we want to save between 24 and 36 moves, we can take the 22-move shortcut and then take the specific shortcut (from ring 1 or 2) that gets us the remaining savings.
- If we want to save 38, 40, or 42 moves, we can take the 22-move and 14-move shortcuts and then the 2, 4, or 6-move shortcut from ring 1.
- We already established that we cannot save 44 moves or more (since then
would be less than ).
Generalizing this strategy: we can find the number of moves we need to save
(which is
- If
is greater than or equal to the number of moves saved by the largest shortcut (i.e., moves), we take that shortcut, subtract its savings from , and proceed to the -th ring. - If
is equal to the number of moves saved by some other shortcut in ring (i.e., , , or ), we take that shortcut and stop. (We must be careful not to do this when , since that move — from cell to cell — saves us nothing and is not a shortcut! - Otherwise, we reject all shortcuts in ring
, and proceed to ring .
All that remains is to find the room numbers for the shortcuts that we take.
Instead of trying to generate the entire spiral, we can notice that, say,
the upper left corners of the rings (starting in the central cell and going
outward) have values
Once we have the number of the upper left cell of a ring, it is not too
hard to find the values of the cells we are using for shortcuts in that ring
(i.e., the ones in the central row or column). If the upper left cell's
number is
Because there are
It could have been worse...
We thought about presenting this problem in a different way, without
mentioning spirals: starting from the upper left cell of an
Comments