Hints for SRM 647, D1, 500-Pointer (CtuRobots)
James S. Plank
Fri Jan 30 11:56:42 EST 2015
Problem Statement.
This problem was a little overwhelming live, as I had no clue how to solve it. But I simply
bit off what I could, and then the solution evolved.
Let's ask ourselves a few questions:
- Question 1: Given just two robots with capacities a and b that go
in order, what's the maximum distance that the second robot will travel?
Clearly, the second robot will go half the distance of its fuel, plus half the distance of
the fuel it gets from the first robot. To maximize the amount of fuel that it gives to the
second robot, the first robot should travel a/3 units, give a/3 fuel to the second
robot, and then travel back to the start. Think about why:
- If the first robot turns back before a/3 units, it can only donate fuel equal to
the distance that it has traveled, because that's all the capacity that the second robot has.
That amount will be less than a/3.
- If the first robot turns back after a/3 units, then it will have to donate less
than a/3 units in order to have enough to get back to the start.
So, this means that the second robot will travel a maximum of b/2 + a/6 units.
- Question 2: So, given two robots with capacities a and b, how should
they be ordered?
Let's compare -- when is:
a/2 + b/6 > b/2 + a/6?
It's a simple matter of algebra to show that it's when a > b. Good -- now we know
how to order two robots. In fact, if you think about it, this means that if you have any
number of robots, the one with the greatest capacity should go last.
- Question 3: Now, given two robots with capacities a and b that are
not the last robots, suppose robot b goes before robot a. How much fuel will
they donate to the next robot?
The equation here is going to be: a/3 + b/9. It's an easy matter to show that
in order to maximize this quantity, a should be greater than b.
So now we know a very important fact -- given a collection of nrobots, we should order them
in ascending order of capacity to maximize their distance. Calculating the distance is a
really easy O(n) operation.
So now that we know how to calculate the best distance given a collection of robots, we can
turn our attention to choosing the robots. It seems quite natural to me to sort the robots
in decreasing order of capacity. Then start to think of a systematic way to calculate
distances:
- Suppose we select the first robot to be in our set. It will be the
last robot to go. Suppose its cost is c. Then the maximum distance will be determined
by the maximum amount of fuel that the remaining robots can provide, subject to the constrain that
their total cost is less than or equal to B - c.
- Suppose we don't select the first robot to be in our set, but we do select the second.
It will now be the
last robot to go. Suppose its cost is c. Then the maximum distance will be determined
by the maximum amount of fuel that the remaining robots can provide, subject to the constrain that
their total cost is less than or equal to B - c.
This feels like a dynamic program. Let's suppose our vector of ordered robots is v.
Then, for each i, we want to know what the maximum distance is if we choose robot
v[i] as the one to go last. That means we will not be choosing any robots with indices
less than i. Moreover, suppose the cost of that robot is c. Then, we want
to find the maximum amount of fuel that we can get from robots with indices greater than i,
whose total cost is less than or equal to B-c.
So, define the procedure MF(index,budget) to be the maximum amount of fuel that can
be donated by robots whose indices in v are greater than or equal to index and
whose total cost is less than or equal to budget. This will be a recursive procedure
with the following cases:
- Case 1: If index is equal to v.size() than the answer is zero.
- Case 2: If you don't include robot v[index], then
MF(index,budget) will be equal to
MF(index+1,budget).
- Case 3: Suppose the cost of robot v[index] is equal to c, and suppose
that this cost is less than or equal to budget. Then you need to decide whether it's
best not to include the robot (which is case 2), or to include the robot. If you do include
the robot, then the amount of fuel that it donates will
be 1/3 of its capacity plus 1/3 of MF(index+1,budget-c).
This gives you a recursive procedure to write, and of course you should see that it has to
be memoized. The cache's maximum size will be v.size() * budget -- the constraints
limit that to 5,000,000, so we're good to fit into topcoder's time limit.
Happy hacking!