Optimal Strategy for the Divisor game using Dynamic Programming
Given an integer N and two players, A and B are playing a game. On each player’s turn, that player makes a move by subtracting a divisor of current N (which is less than N) from current N, thus forming a new N for the next turn. The player who does not have any divisor left to subtract loses the game. The task is to tell which player wins the game if player A takes the first turn, assuming both players play optimally.
Examples:
Input : N = 2
Output : Player A wins
Explanation :
Player A chooses 1, and B has no more moves.
Input : N = 3
Output : Player B wins
Explanation :
Player A chooses 1, player B chooses 1, and A has no more moves.
Approach :
This problem mentioned above can be solved using Dynamic Programming.
- We will take a DP having 2 states i.e.
N -> current number left
A -> boolean value to decide if it’s player A’s turn or not
-
- At each state, we will try to find all the divisors of N and will try to find the next state where the current player is winning. For player A, we will try to find the next state where the return value is true while for player B, we will try to find the next state where the return value is false (as false represents the loss of player A).
- The base cases will be for N=1 where always the player A will lose and N=2 where always the player B will lose.
- To find the answer, we just need to find the value of DP[ N ][ 1 ].
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
bool divisorGame( int N, bool A, int dp[][2])
{
if (N == 1 or N == 3)
return false ;
if (N == 2)
return true ;
if (dp[N][A] != -1)
return dp[N][A];
int ans = (A == 1) ? 0 : 1;
for ( int i = 1; i * i <= N; i++) {
if (N % i == 0) {
if (A)
ans |= divisorGame(N - i, 0, dp);
else
ans &= divisorGame(N - i, 1, dp);
}
}
return dp[N][A] = ans;
}
int main()
{
int N = 3;
int dp[N + 1][2];
memset (dp, -1, sizeof (dp));
if (divisorGame(N, 1, dp) == true )
cout << "Player A wins" ;
else
cout << "Player B wins" ;
return 0;
}
|
Java
import java.util.*;
class GFG {
static int divisorGame( int N, int A, int dp[][]) {
if (N == 1 || N == 3 )
return 0 ;
if (N == 2 )
return 1 ;
if (dp[N][A] != - 1 )
return dp[N][A];
int ans = (A == 1 ) ? 0 : 1 ;
for ( int i = 1 ; i * i <= N; i++) {
if (N % i == 0 ) {
if (A == 1 )
ans |= divisorGame(N - i, 0 , dp);
else
ans &= divisorGame(N - i, 1 , dp);
}
}
return dp[N][A] = ans;
}
public static void main(String[] args) {
int N = 3 ;
int [][] dp = new int [N + 1 ][ 2 ];
for ( int i = 0 ; i < N + 1 ; i++) {
for ( int j = 0 ; j < 2 ; j++) {
dp[i][j] = - 1 ;
}
}
if (divisorGame(N, 1 , dp) == 1 )
System.out.print( "Player A wins" );
else
System.out.print( "Player B wins" );
}
}
|
Python3
from math import sqrt
def divisorGame(N,A,dp):
if (N = = 1 or N = = 3 ):
return False
if (N = = 2 ):
return True
if (dp[N][A] ! = - 1 ):
return dp[N][A]
if (A = = 1 ):
ans = 0
else :
ans = 1
for i in range ( 1 , int (sqrt(N)) + 1 , 1 ):
if (N % i = = 0 ):
if (A):
ans | = divisorGame(N - i, 0 , dp)
else :
ans & = divisorGame(N - i, 1 , dp)
dp[N][A] = ans
return dp[N][A]
if __name__ = = '__main__' :
N = 3
dp = [[ - 1 for i in range ( 2 )] for j in range (N + 1 )]
if (divisorGame(N, 1 , dp) = = True ):
print ( "Player A wins" )
else :
print ( "Player B wins" )
|
C#
using System;
class GFG {
static int divisorGame( int N, int A,
int [,]dp)
{
if (N == 1 || N == 3)
return 0;
if (N == 2)
return 1;
if (dp[N, A] != -1)
return dp[N, A];
int ans = (A == 1) ? 0 : 1;
for ( int i = 1; i * i <= N; i++)
{
if (N % i == 0)
{
if (A == 1)
ans |= divisorGame(N - i, 0, dp);
else
ans &= divisorGame(N - i, 1, dp);
}
}
return dp[N, A] = ans;
}
public static void Main(String[] args)
{
int N = 3;
int [,] dp = new int [N + 1, 2];
for ( int i = 0; i < N + 1; i++)
{
for ( int j = 0; j < 2; j++)
{
dp[i, j] = -1;
}
}
if (divisorGame(N, 1, dp) == 1)
{
Console.Write( "Player A wins" );
}
else
{
Console.Write( "Player B wins" );
}
}
}
|
Javascript
<script>
function divisorGame(N, A, dp) {
if (N == 1 || N == 3)
return false ;
if (N == 2)
return true ;
if (dp[N][A] != -1)
return dp[N][A];
let ans = (A == 1) ? 0 : 1;
for (let i = 1; i * i <= N; i++) {
if (N % i == 0) {
if (A)
ans |= divisorGame(N - i, 0, dp);
else
ans &= divisorGame(N - i, 1, dp);
}
}
return dp[N][A] = ans;
}
let N = 3;
let dp = [];
for (let i = 0; i < N + 1; i++) {
let temp = [-1]
for (let j = 0; j < 2; j++) {
temp.push([-1])
}
dp.push(temp)
}
if (divisorGame(N, 1, dp) == true )
document.write( "Player A wins" );
else
document.write( "Player B wins" );
</script>
|
Time Complexity: O(N*log(N))
Auxiliary Space: O(N)
Last Updated :
10 Mar, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...