Solution
Here is a quadratic solution that uses dynamic programming in a naive way.
We first pre-compute the minimum number of pushes needed to move any robot from one grid to another. We can solve this as an all-pair shortest path problem on a directed, unweighted, graph
, where every vertex is a grid and an edge
exists if a single push would move the robot from
to
. Denote
as the minimum number of pushes to send a robot from
to
.
if it is not possible to reach
from
. This step can be computed in
time. In the graph we constructed, each vertex has at most four outgoing edges (one for each direction). Therefore,
and this step takes
time.
Note that we only need to keep track of grid locations that are reachable by the robots. In the worst case,
is
but in practice, if the number of occlusions is small,
.
We then compute the following: Given two compatible robots at grids
and
, how many pushes are needed if they are to merge in location
? The number of pushes is the sum of the minimum cost from
to
and
to
. The order we push the robots does not matter.
Next, we need to determine the order of merging. The order can be modelled as a binary tree with the individual robots as leaf nodes and composite robots as intermediate nodes. The solution is thus to find, among all possible binary trees of
nodes, the tree that requires the fewest number of pushes. The solution can be achieved with dynamic programming.
Let
be the minimum number of pushes it takes to merge robots
to
, with the final merge taking place at grid
. The final answer to the task ROBOTS is
.
Let
be the minimum number of pushes it takes to merge robots
to
in some grid AND move it to grid
. In other words,

Here is the dynamic programming solution. First, we consider the base case, and initialize
to
if robot
is located at grid
initially.
For the recursive case, we have

for
.
Translating the equations above directly, we have our first solution, presented in Algorithm 1. The algorithm runs in
time, with Line 19 and computation of
being the bottleneck. Note that since
, we treat the factor
in the running time as a constant.
(too lazy to copy Algorithm 1)
Solution
To improve the running time, we need to find a faster way to compute
and avoid computing
. The key insight is that if
has not been determined, and
is reachable from some grid location
in one push (i.e.,
), then
. Further, we know that if
and
merge at
, then
.
For ease of exposition, we abuse the notation of
to represent "minimum-so-far" in the following explanation and pseudocode, instead of the minimum.
The improved algorithm to compute
is similar to that of Dijkstra's algorithm. We say that we relax a vertex
if we set
to
when
and
. We maintain a priority queue containing the "front" of vertices we are exploring, initialized with vertices corresponding to the merged locations. The main loop expands the front and keeps relaxing vertices until there are no more vertices to relax. When this happens, we know that each of the
already contains its minimum value.
Note that this algorithm to compute
no longer makes use of
. It turns out that we do not require
during initialization as well, as
can be initialized by repeatedly relaxing the vertices. The removal of
removes the bottleneck
from the algorithm.
The pseudocode for this improved algorithm is shown in Algorithm 2. Note that the looping condition at Line 11 has changed to accommodate the calculation of
.
In the worst case, each vertex is inserted into the queue once for each incoming neighbor. Thus, there are
insertions, each taking
time using a binary heap implementation of a priority queue. Since
, the running time for this version of the algorithm takes
time.
Solution
We now present the final solution, relying on the observations that: (O1) the value of
is bounded and is an integer, and (O2) we always insert an item with a key larger than the current minimum in Line 29.
Let's begin by bounding the value of
. We will present a very loose bound here for simplicity. For any two robots
and
to merge, in the worst case, they must (collectively) visit every reachable grid (each requiring one push). After merging, the composite robot may be pushed to each of the reachable grid again, before reaching
. This simple analysis gives an upper bound for
for any
, and
, as
.
Since the key value of the priority queue is an integer and is bounded, we can implement the priority queue as (i) an array of lists
, where
stores a list of grid locations
such that
, and (ii) a value
, such that
is the non-empty list with the smallest index.
The
operation (Lines 20 and 29) simply appends an item
to the end of the list
and updates
if necessary. This operation takes
time. The
operation (Line 25) simply returns an item from the list
and scans for the next higher
if
becomes empty. Observation O2 implies that it suffices to make a single pass through the list (i.e.,
always increases inside the while loop starting at Line 24). Summing up the cost of every
operation, the running time is
. Therefore, with this implementation of the priority queue, the total running time for the algorithm is reduced to
.
(too lazy to copy Algorithm 2)
Credits
Task statement and
solution by Wei Tsang Ooi.
solution by Harta Wijaya.
solution by Raymond Kang and Harta Wijaya.
Comments