I need some help with a problem. I recently got this in an interview and I was trying to solve it but having no luck. Here's the question:
Code an algorithm for a game consisting of two players. The input is a positive integer x. Each round, a player deducts a perfect square from the number. The player can choose any perfect square as long as it is less than or equal to the current number and greater than 0. The current player wins if the number becomes 0 after his deduction.
I suppose this should be done using dynamic programming/greedy approach which I am not very well verse with. Or we might need to come up with a sequence of winning/losing numbers and if a player ends up in a winning sequence, he will win no matter what. But how do we come up with such a sequence?
Can anyone help me solve this question possibly in Java?
UPDATE:
Solution 1 as suggested by DAle:
public int subtractPerfectSquares(int n)
{
if (n <= 0)
return 1;
boolean[] isWinningCase = new boolean[n + 1];
for (int i = 1; i <= n; i++)
{
for (int num = 1; num * num <= i; num++)
{
if (!isWinningCase[i - (num * num)])
{
isWinningCase[i] = true;
break;
}
}
}
return isWinningCase[n] ? 1 : 2;
}
Solution2 modified for better understanding:
public int subtractPerfectSquares2(int n)
{
if (n <= 0)
return 1;
boolean[] isWinningCase = new boolean[n + 1];
// if we reach 0, we win
isWinningCase[0] = true;
// 1 is a win
isWinningCase[1] = true;
// 2 is a losing condition. We must define this as this state dictates losing scenarios for further states
isWinningCase[2] = false;
// we start from 3
for (int i = 3; i <= n; i++)
{
for (int num = 1; num * num <= i; num++)
{
int prefectSquare = num * num;
// if we get to 0 from current number or if we get to a losing scenario (to be faced by next player) from current number, then the current state is a winning position
if (i - prefectSquare == 0 || !isWinningCase[i - prefectSquare])
{
isWinningCase[i] = true;
break;
}
}
}
// return player 1 if given number is a winning state else player 2 wins
return isWinningCase[n] ? 1 : 2;
}
The only difference between players in this game is that player 1 goes first. This type of games is called impartial game and the perfect strategies of both players are identical. Furthermore, we can divide all states (integer x
) of the game into two types: winning position or losing position using the following rules:
x=0
is a losing positionx
is a winning position if there is at least one possible move that leads to a losing position.x
is a losing position if every possible move leads to a winning position.Then we need to determine the type of all positions from 1
to x
. Possible implementation:
boolean[] isWinning = new boolean[x+1];
for (int state = 0; state <= x; ++state) {
isWinning[state] = false;
for (int i = 1; i*i <= state; ++i) {
int perfectSquare = i*i;
if (!isWinning[state - perfectSquare]) {
isWinning[state] = true;
break;
}
}
}
If the current player is in the winning position (isWinning[x] == true
), you should choose such perfect square that isWinning[x - perfectSquare] == false
. This will bring the game (and another player) to a losing position. If the player is in the losing position, nothing could save him, every possible perfect square is equally bad.