Sunday, January 18, 2015

Hackerrank: Stone Piles



Problem Statement
Stone Piles

 https://www.hackerrank.com/challenges/stone-piles
 
There are N piles of stones where the ith pile has xi stones in it. Alice and Bob play the following game:
  1. Alice starts, and they alternate turns.
  2. In a turn, a player can choose any one of the piles of stones and divide the stones in it into any number of unequal piles such that no two of the newly created piles have the same number of stones. For example, if there 8 stones in a pile, it can be divided into one of these set of piles: (1,2,5), (1,3,4), (1,7), (2,6) or (3,5). 
  3. The player who cannot make a move (because all the remaining piles are indivisible) loses the game.
Given the starting set of piles, who wins the game assuming both players play optimally?

Input:
The first line contains the number of test cases T. T test cases follow. The first line for each test case contains N, the number of piles initially. The next line contains N space delimited numbers, the number of stones in each of the piles.

Output:
Output T lines, one corresponding to each test case containing "ALICE" if Alice wins the game and "BOB" otherwise.

Constraints:
1 ≤ T ≤ 50
1 ≤ N ≤ 50
1 ≤ xi ≤ 50
Sample Input
4  
1  
4  
2  
1 2  
3  
1 3 4  
1  
8
Sample Output
BOB  
BOB  
ALICE  
BOB
 
Explanation
For the first case, the only possible move for Alice is (4) -> (1,3). Now Bob breaks up the pile with 3 stones into (1,2). At this point Alice cannot make any move and has lost.




Solution:
To solve this problem we need some basic knowledge in game theory. There is a well-written tutorial about impartial games online. (http://web.mit.edu/sp.268/www/nim.pdf)

Now back to our problem. The basic idea is to compute the Sprague-Grundy function. We can apply the same argument about the Nim game mentioned in the tutorial, meaning if we have SG function eaqual to zero in the current step, we will get a non-zero value in the next step and if we have a non-zero value at current step, we can always construct a strategy  that brings the value to zero again.

Given the initial array, we can compute the SG value, if it is zero then print "BOB", otherwise print "ALICE".

Code:


#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <vector>
#include <climits>
#include <list>
#include <unordered_map>
#include <algorithm>

using namespace std;


typedef vector< vector<bool> > myVector;


void compute_sg_fun(int prev, int start, int rest, int key, vector<int>& sg_fun, myVector& record) {

 for (int i = start; i <= rest / 2; i++) {
  if (rest-i > i) {
   int res = prev ^ sg_fun[i] ^ sg_fun[rest-i];
   record[key][res] = true;
   compute_sg_fun(prev ^ sg_fun[i], i+1, rest - i,key, sg_fun, record);
  }
 }

 int k = 0;

 while (record[key][k]) ++k;

 sg_fun[key] = k;
}






int main(void)


{

 myVector record(51, vector<bool>(51,false));
 vector<int> sg_fun(51,-1);
 sg_fun[0] = 0;
 sg_fun[1] = 0;
 sg_fun[2] = 0;
 sg_fun[3] = 1;


 for (int i = 4; i <= 50; i++) compute_sg_fun(0,1,i,i,sg_fun,record);
 
 int t; cin >> t;

 for (int i = 0; i < t; i++) {
  int n;
  cin >> n;

  int res = 0;

  for (int j = 0; j < n; j++) {
   int c; cin >> c;
   res = res ^ sg_fun[c];
  }

  printf("%s\n", res == 0 ? "BOB" : "ALICE");

 }

 return 0;

}









No comments:

Post a Comment