SRM 619, D1, 250-Pointer (SplitStoneGame)

James S. Plank

Writeup: Sat Nov 19 11:37:24 EST 2016
Latest revision: Fri Nov 13 10:07:32 EST 2020

In case Topcoder's servers are down, here is a summary of the problem:
Examples (these are compiled into the main.cpp program):

Example Input Output Comments
0 { 1, 1, 1 } "LOSE" There is no pile with more than one stone, so you can't make a move.
1 { 2, 2 } "LOSE" You can pick up a pile, but there is only one pile left.
2 { 1, 1, 2 } "WIN" If you split the last pile into the other two, you have the previous game.
3 {1, 2, 3, 4, 3, 2, 2, 4, 3, 1, 4, 4, 1, 2, 4, 4, 1, 4, 3, 1, 4, 2, 1} "WIN"
4 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 3, 1, 9, 1, 3, 1, 1, 1, 1, 1} "LOSE"
5 { 1, 2, 50} "WIN"


Testing yourself

Besides the initial six examples, you can generate random input by giving higher values as the command line argument. It will take the argument mod 1000 and add one, and then generate random input. The shell script tests.sh should produce answers.txt.

Hints

There's a temptation on problems like this to figure out the answer using your brain. That may well be possible, but I prefer to see if dynamic programming works, because then I don't have to think as hard. Remember the Towers of Hanoi: when you solve it with recursion, you don't have to think about which disk to move first -- the recursion does it for you.

So with the problem, take a standard dynamic programming approach: Figure out how to solve it recursively, then make it faster through memoization, removing recursion, etc.

There's one big observation to make, which makes this problem much simpler than it appears. That is that if a pile has more than one stone, then it doesn't matter how many stones it has. You can thus represent the state of the piles with two values, "one" and "more than one." To help you see this, consider the example from the problem writeup, where the piles are { 1, 2, 50 }. Instead, you can represent them as:

{ one, more-than-one, more-than-one }.

Any move that Shiny makes will turn the piles into:

{ more-than-one, more-than-one }.

And that's a losing state for whoever is playing Shiny!

Now, after working through that example, you can observe that you don't need a big array to hold the game state. You just need two numbers:

The examples can be represented as follows: So, write a method with the following prototype:

string WL(int O, int M);

This returns whether one wins or loses when there are O piles with one stone, and M piles with more than one stone. I will leave it to you to figure out the base cases, and the recursion.

You can solve all of the examples without memoization, so that you can see the answers. Examples 3 and 4 will be too slow, though, so you should then memoize. Then, you're done!