Skip to content
Related Articles

Related Articles

Improve Article

Find the winner of a game of removing at most 3 stones from a pile in each turn

  • Difficulty Level : Medium
  • Last Updated : 12 Jun, 2021

Given an array arr[] of size N, denoting values assigned to N stones, two players, Player1 and Player2, play a game of alternating turns. In each turn, a player can take 1, 2, or 3 stones from the first remaining stones with the sum of values of all the removed stones added to the player’s score. Considering that both players play optimally, the task is to print the the winner of the game. If both the players end the game with the same score, print “Tie”.

Examples:

Input: arr[] = {1, 2, 3, 7}
Output: Player2
Explanation: Player1 will always lose in an optimal scenario.

Input: arr[] = {1, 2, 3, -9}
Output: Player1
Explanation: Player1 must choose all the three piles at the first move to win and leave Player2 with negative score.
If Player1 chooses only one stone his score will be 1 and the next move Player2 score becomes 5. 
The next move Player1 will take the stone with value = -9 and lose.
If Player1 chooses two piles his score will be 3 and the next move Player2 score becomes 3. 
The next move Player1 will take the stone with value = -9 and also lose.

Naive Approach: The simple approach is to pick the number of stones that will maximize the total sum of the stone’s values. As both players play optimally and Player1 starts the game, Player1 picks either 1 or 2 or 3 stones and the remaining stones passed to the next player. Therefore, the score of Player2 must be subtracted from score of Player1. The idea is to use recursion to solve the problem. Let the maximum score of Player1 be res which is obtained after the recursive calls.



  • If the result, res > 0, Player1 wins
  • If the result, res < 0, Player2 wins
  • If the result, res == 0, then it is a tie.

The recursive tree looks like this, where some subproblems are repeated many times.

Follow the steps to solve the problem:

  • Declare a recursive function, say maxScore(i), to calculate the maximum score of Player1 if the game starts at index i
    • If the value of i ≥ n, return 0.
    • Initialize a variable, say score as INT_MIN, to store the maximum score of Player1
      • Picks 1 stone: score = max(score, arr[i] – maxScore(i + 1))
      • Picks 2 stones i.e (i + 1 < N): score = max(score, arr[i] + arr[i + 1] – maxScore(i + 2))
      • Picks 3 stones i.e (i + 2 < N): score = max(score, arr[i] + arr[i + 1] + arr[i + 2] – maxScore(i + 3))
    • Return the value of score.
  • Store the value of maxScore(0) in a variable res.
  • If the value of res>0, print “Player1”, if res<0, print “Player2”, otherwise print “Tie”.

Below is the implementation of the above approach:

C++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the maximum score of Player1
int maximumStonesUtil(int* arr, int n, int i)
{
    // Base Case
    if (i >= n)
        return 0;
 
    // Variable to store maximum score
    int ans = INT_MIN;
 
    // Pick one stone
    ans = max(ans,
              arr[i] - maximumStonesUtil(arr, n, i + 1));
 
    // Pick 2 stones
    if (i + 1 < n)
        ans = max(ans,
                  arr[i] + arr[i + 1]
                      - maximumStonesUtil(arr, n, i + 2));
 
    // Pick 3 stones
    if (i + 2 < n)
        ans = max(ans,
                  arr[i] + arr[i + 1] + arr[i + 2]
                      - maximumStonesUtil(arr, n, i + 3));
 
    // Return the score of the player
    return ans;
}
 
// Function to find the winner of the game
string maximumStones(int* arr, int n)
{
    // Store the result
    int res = maximumStonesUtil(arr, n, 0);
 
    // Player 1 wins
    if (res > 0)
        return "Player1";
 
    // PLayer 2 wins
    else if (res < 0)
        return "Player2";
 
    // Tie
    else
        return "Tie";
}
 
// Driver Code
int main()
{
    // Given Input
    int arr[] = { 1, 2, 3, 7 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    // Function Call
    cout << maximumStones(arr, n);
 
    return 0;
}

Java




// Java program for the above approach
class GFG{
 
// Function to find the maximum score of Player1
static int maximumStonesUtil(int[] arr, int n,
                             int i)
{
     
    // Base Case
    if (i >= n)
        return 0;
 
    // Variable to store maximum score
    int ans = Integer.MIN_VALUE;
 
    // Pick one stone
    ans = Math.max(ans, arr[i] - maximumStonesUtil(
                     arr, n, i + 1));
 
    // Pick 2 stones
    if (i + 1 < n)
        ans = Math.max(ans, arr[i] + arr[i + 1] -
               maximumStonesUtil(arr, n, i + 2));
 
    // Pick 3 stones
    if (i + 2 < n)
        ans = Math.max(
            ans,
            arr[i] + arr[i + 1] + arr[i + 2]
                - maximumStonesUtil(arr, n, i + 3));
 
    // Return the score of the player
    return ans;
}
 
// Function to find the winner of the game
static String maximumStones(int[] arr, int n)
{
     
    // Store the result
    int res = maximumStonesUtil(arr, n, 0);
 
    // Player 1 wins
    if (res > 0)
        return "Player1";
 
    // PLayer 2 wins
    else if (res < 0)
        return "Player2";
 
    // Tie
    else
        return "Tie";
}
 
// Driver code
public static void main(String[] args)
{
    int arr[] = { 1, 2, 3, 7 };
    int n = arr.length;
 
    // Function Call
    System.out.println(maximumStones(arr, n));
}
}
 
// This code is contributed by abhinavjain194

Python3




# Python3 program for the above approach
import sys
 
# Function to find the maximum score of Player1
def maximumStonesUtil(arr, n, i):
     
    # Base Case
    if (i >= n):
        return 0
 
    # Variable to store maximum score
    ans = -sys.maxsize-1;
 
    # Pick one stone
    ans = max(
        ans, arr[i] - maximumStonesUtil(
                       arr, n, i + 1))
 
    # Pick 2 stones
    if (i + 1 < n):
        ans = max(
            ans, arr[i] + arr[i + 1]- maximumStonesUtil(
                      arr, n, i + 2))
 
    # Pick 3 stones
    if (i + 2 < n):
        ans = max(
            ans, arr[i] + arr[i + 1] + arr[i + 2]-
                 maximumStonesUtil(arr, n, i + 3));
 
    # Return the score of the player
    return ans
 
# Function to find the winner of the game
def maximumStones(arr, n):
     
    # Store the result
    res = maximumStonesUtil(arr, n, 0)
 
    # Player 1 wins
    if (res > 0):
        return "Player1"
 
    # PLayer 2 wins
    elif(res < 0):
        return "Player2"
 
    # Tie
    else:
        return "Tie"
 
# Driver Code
if __name__ == '__main__':
     
    # Given Input
    arr = [ 1, 2, 3, 7 ]
    n = len(arr)
 
    # Function Call
    print(maximumStones(arr, n))
 
# This code is contributed by SURENDRA_GANGWAR

C#




// C# program for the above approach
using System;
         
class GFG
{
 
// Function to find the maximum score of Player1
static int maximumStonesUtil(int[] arr, int n,
                             int i)
{
     
    // Base Case
    if (i >= n)
        return 0;
 
    // Variable to store maximum score
    int ans = Int32.MinValue;
 
    // Pick one stone
    ans = Math.Max(ans, arr[i] - maximumStonesUtil(
                     arr, n, i + 1));
 
    // Pick 2 stones
    if (i + 1 < n)
        ans = Math.Max(ans, arr[i] + arr[i + 1] -
               maximumStonesUtil(arr, n, i + 2));
 
    // Pick 3 stones
    if (i + 2 < n)
        ans = Math.Max(
            ans,
            arr[i] + arr[i + 1] + arr[i + 2]
                - maximumStonesUtil(arr, n, i + 3));
 
    // Return the score of the player
    return ans;
}
 
// Function to find the winner of the game
static String maximumStones(int[] arr, int n)
{
     
    // Store the result
    int res = maximumStonesUtil(arr, n, 0);
 
    // Player 1 wins
    if (res > 0)
        return "Player1";
 
    // PLayer 2 wins
    else if (res < 0)
        return "Player2";
 
    // Tie
    else
        return "Tie";
}
     
// Driver Code
public static void Main()
{
    int[] arr = { 1, 2, 3, 7 };
    int n = arr.Length;
 
    // Function Call
    Console.WriteLine(maximumStones(arr, n));
 
}
}
 
// This code is contributed by code_hunt.
Output: 
Player2

 

Time Complexity: O(3N)
Auxiliary Space: O(N)

Efficient Approach: To optimize the above approach, the idea is to use dynamic programming. The given problem has optimal substructure property and overlapping subproblems. Use memoization by creating a 1D table, dp of size N to store the results of the recursive calls. 

Below is the implementation of the above approach: 

C++




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to find the maximum score of Player 1
int maximumStonesUtil(int* arr, int n, int i,
                      vector<int>& dp)
{
    // Base Case
    if (i >= n)
        return 0;
 
    int& ans = dp[i];
 
    // If the result is already computed, then
    // return the result
    if (ans != -1)
        return ans;
 
    // Variable to store maximum score
    ans = INT_MIN;
 
    // Pick one stone
    ans = max(
        ans, arr[i] - maximumStonesUtil(arr, n, i + 1, dp));
 
    // Pick 2 stones
    if (i + 1 < n)
        ans = max(ans, arr[i] + arr[i + 1]
                           - maximumStonesUtil(arr, n,
                                               i + 2, dp));
 
    // Pick 3 stones
    if (i + 2 < n)
        ans = max(ans, arr[i] + arr[i + 1] + arr[i + 2]
                           - maximumStonesUtil(arr, n,
                                               i + 3, dp));
 
    // Return the score of the player
    return ans;
}
 
// Function to find the winner of the game
string maximumStones(int* arr, int n)
{
    // Create a 1D table, dp of size N
    vector<int> dp(n, -1);
 
    // Store the result
    int res = maximumStonesUtil(arr, n, 0, dp);
 
    // Player 1 wins
    if (res > 0)
        return "Player1";
 
    // PLayer 2 wins
    else if (res < 0)
        return "Player2";
 
    // Tie
    else
        return "Tie";
}
 
// Driver Code
int main()
{
    // Given Input
    int arr[] = { 1, 2, 3, 7 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    // Function Call
    cout << maximumStones(arr, n);
 
    return 0;
}
Output: 
Player2

 

Time Complexity: O(N)
Auxiliary Space: O(N)

 

Attention reader! Don’t stop learning now. Get hold of all the important mathematical concepts for competitive programming with the Essential Maths for CP Course at a student-friendly price. To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.




My Personal Notes arrow_drop_up
Recommended Articles
Page :