**Question**: There are n coins in a line. Two players take turns to take a coin from one of the ends of the line until there are no more coins left. The player with the larger amount of money wins. Assume that you go first, describe an algorithm to compute the maximum amount of money you can win.**Answer**: If we assume that n is even then there is simple strategy to ensure that you win. Find the sum of coins at even and odd positions say X and Y respectively. Now if X>Y, pick coins only at even positions else pick coins only at odd positions.**How to ensure that you pick coins only at even or odd positions**:

Assume that n = 6 and value are {3, 2, 2, 3, 1, 2}. Then sum at even positions is 7 (2 +3 +2) and at odd positions is 6 (3 +2 +1). So you will always pick the coins at even positions to ensure wining. How to achieve it:

**Is above strategy optimal**:

Above strategy ensure you winning but doesn’t ensure that you are drawing the maximum amount of money. For previous example {3, 2, 2, 3, 1, 2}, you drew a sum of 7, but you could have drawn a sum of 8. Lets see how:

Pick the first coin (3) instead. The opponent is left with two possible choices, the left coin (2) and the right coin (2), both valued at 2. No matter, which coin the opponent chose, you can always take the other coin (2) next and the configuration of the coins becomes: {2, 3, 1}. Now, the coin in the middle (3) would be yours to keep for sure. Therefore, you win the game by a total amount of 3 + 2 + 3 = 8, which proves that the previous non-losing strategy is not necessarily optimal.

**An optimal Solution**:

Since your opponent is as smart as you, so we need to take all the possible combinations in consideration before our move. Calculating all those moves will include repetitive calculations so this is the place where we can use Dynamic Programming to show its magic.

Say coins are in stored in array A and C(i, j) is the maximum sum possible when remaining coins are from i to j. Lets discuss the case when there are remaining coins from i to j (positions) and it’s your turn to pick the coin. Now there are 2 possibilities:

- You pick coin A(i)
- You pick coin A(j)

**Case 1 - If you pick coin Ai**: Then the opponent has the choice between A(i+1) and A(j). If the opponent takes A(i+1), the remaining coins are { A(i+2) … A(j)}, for which our maximum is denoted by C(i+2, j). On the other hand, if the opponent takes Aj our maximum is C(i+1, j-1). Since the opponent is as smart as you, he would have chosen the choice that yields the minimum amount to you.

Therefore, the maximum amount you can get when you choose Ai is:

C1 = Ai + min { C(i+2, j), C(i+1, j-1) }

**Case 2 - If you pick coin Aj**:

Similar to case 1, the maximum amount you can get when you choose Aj is:

ThereforeC2 = Aj + min { C(i+1, j-1), C(i, j-2) }

C(i, j) = max { C1, C2 }

= max { Ai + min { C(i+2, j), C(i+1, j-1) },

Aj + min { C(i+1, j-1), C(i, j-2) } }

Now we have the recursive function in hand and the above recurrence relation could be implemented in few lines of code. But if we follow simple recursion, its complexity is exponential. The reason is that each recursive call branches into a total of four separate recursive calls, and it could be n levels deep from the very first call).

To reduce the time complexity, we need to store the intermediate values in a table and use them, when required. Memoization provides an efficient way by avoiding re-computations using intermediate results stored in a table.

If you notice, we do not need to build complete matrix but only need to build right (upper) triangular matrix. Also notice that C[i, i] (diagonal elements) will always be equal to A[i]. Below is the code which runs in O(n^2) time and takes O(n^2) space.

**Code**:

#define MAX 100

int maxMoney(int A[], int N) {

int C[MAX][MAX] = {0};

int x, y, z; //x = C[m+2][n], y = C[m+1][n-1], z = C[m][n-2]

for (int i = 0; i < N; i++) {

for (int m = 0, n = i; n < N; m++, n++) {

//calculate x, y, z

x = (m+2 < N) ? C[m+2][n] : 0;

y = (m+1 < N && n-1 >= 0) ? C[m+1][n-1] : 0;

z = (n-1 > 0) ? C[m][n-2] : 0;

C[m][n] = max(A[m] + min(x,y),

A[n] + min(y,z));

//For Debugging

cout << x << ", " << y << ", " << z << endl;

cout << m << ", " << n << ", " << C[m][n] << endl;

}

}

return C[0][N-1];

}

**Subscribe**- To get an automatic feed of all future posts subscribe here, or to receive them via email go here and enter your email address in the box. You can also like us on facebook and follow me on Twitter @akashag1001.
AnonymousCan you explain how you arrive at the 2 for loops. I understand the recursive equation but have a hard time to convert them to code.

Akash@Anonymous: Yes, as I have already said that we need just upper triangular matrix and by seeing the dependency, we can see which elements we need to find a specific element. If you print the matrix at every iteration, you will get an actual understanding.

denialthank you for your great work

AkashThanks Denial...

archit maheshwarivery good and appreciable work!!....

Shai EphraimHey Akash,

I have encountered a simmilar question

I have two stacks of coins. In my turn I can take the top coin from one of the stacks.

My opponent is smart as me.

What is the maximum amount of money I can get in the end(Coins may have different value' but they are all positive)

AnonymousGood approach. Just one observation: The matrix needs to be built starting at the right hand bottom corner. Bottom to top, left to right. This is because C[i][j] requires cells in rows i+1, i+2 and cols j-1,j-2 to be available.

Thanks

-A