Reputation: 190
Alice and Bob play the following game:
1) They choose a permutation of the first N numbers to begin with.
2) They play alternately and Alice plays first.
3) In a turn, they can remove any one remaining number from the permutation.
4) The game ends when the remaining numbers form an increasing sequence. The person who played the last turn (after which the sequence becomes increasing) wins the game.
Assuming both play optimally, who wins the game?
Input: The first line contains the number of test cases T. T test cases follow. Each case contains an integer N on the first line, followed by a permutation of the integers 1..N on the second line.
Output: Output T lines, one for each test case, containing "Alice" if Alice wins the game and "Bob" otherwise.
Sample Input:
2
3
1 3 2
5
5 3 2 1 4
Sample Output:
Alice
Bob
Constraints:
1 <= T <= 100
2 <= N <= 15
The permutation will not be an increasing sequence initially.
I am trying to solve above problem. I have derived till far but I am stuck at a point. Please help me to proceed further.
In above problem, for permutation of length 2, player 1 always wins.
For a permutation of length 3, player 2 wins if the string is strictly increasing or decreasing.
For a permutation of length 4, If player 1 is able to make the string strictly increasing or decreasing by removing a character, she wins else player 2 wins.
Hence a conclusion is:
If current player is able to make the string strictly increasing he/she wins. (Trivial case)
If he/she is able to make it strictly decreasing the the winner is decided by the number of elements in that sequence. If there are even number of elements in that sequence, current player looses, else wins.
But what should be done if the resultant string is neither increasing nor decreasing??
Upvotes: 7
Views: 6480
Reputation: 391
You can solve it with minimax algorithm. Here is the code in java
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Solution {
public static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
int t = ni();
for(int i=0; i<t; i++){
int n = ni();
Map<Long, Boolean> map = new HashMap<Long, Boolean>();
int[] numbers = new int[n];
for(int j=0; j<n; j++){
numbers[j] = ni();
}
if(aliceWin(numbers, map)) System.out.println("Alice");
else System.out.println("Bob");
}
}
public static boolean aliceWin(int[] a, Map<Long, Boolean> map){
long h = hashCode(a); int temp;
if(map.containsKey(h)) return true;
for(int i=0; i<a.length; i++){
if(a[i]>0){
temp = a[i] ;
a[i] = 0;
if(isIncreasing(a)){
map.put(h, true);
a[i] = temp;
return true;
}
if(!aliceWin(a, map)) {
map.put(h, true);
a[i] = temp;
return true;
}
a[i] = temp;
}
}
return false;
}
public static long hashCode(int[] a){
long result = 0;
for(int i=0; i<a.length; i++){
result = (result << 4) + a[i];
}
return result;
}
public static boolean isIncreasing(int[] a){
int last = 0;
for(int i=0; i<a.length; i++){
if (a[i] > 0){
if(last > a[i]) return false;
last = a[i];
}
}
return true;
}
public static int ni(){
return sc.nextInt();
}
public static void print(Object... args){
System.out.println(Arrays.deepToString(args));
}
}
From blog: hackerrank-permutation-game
Upvotes: 1
Reputation: 409
@tiwo ,@rup COnsidering 5 3 2 1 4 is the sequence first alice removes 5 and the bob removes 2 then the sequence is 3 1 4 which is not in increasing order then alice gets the chance to remove 1 and the the sequence is in ascending order Alice should be the answer. In the graph you gave there should be an edge between 3 and 1 as 1 and 3 are in inversion.
Please tell me where i am wrong as the answer given in the problem is infact BOB
Upvotes: 1
Reputation: 1558
can't we just check at each step that.. does a single change by the next player makes the sequence sorted.. if yes then make some other move.. or carry on with the move
like 5 3 2 1 4 if alice does 3 2 1 4 bob cannot win in a single turn by eliminating any... like if he does 2 1 4 it is nt sorted.. he does 3 1 4 it is nt sorted.. he does 3 2 4 it is nt sorted.. so 5 3 2 1 4 -> 3 2 1 4 is a valid move!!
now is bob's turn.. he'll check the same.. but in some time..there won't be a number such that u can make a move as above.. so u'll have to make a random move and who will win then can be easily calculated by the number of steps tht will make the sequence into single element!!
Upvotes: -1
Reputation: 3349
Of course, this can be done with "brute force" for small N, but don't you suspect an easier answer around inversions and the sign of a permutation?
Originally I suspected an answer like "Alice wins iff the sign is -1, else loses", but this is not the case.
But I would like to propose a representation of the problem that not only your algorithm may use, but one that will equally boost your paper-and-pen performance in this game.
An inversion is a pair of indices i<j such that a[i]>a[j]. Consider (i
,j
) an edge of an undirected graph with vertices 1,...,N. Each player deletes a vertex from this graph and wins if there are no edges left.
For 5 3 2 1 4
, the resulting graph is
5--3
/|\ |
/ | \|
4 1--2
and Alice quickly sees that removing "5" gives Bob the opportunity to remove 2. Then no inversions are left, and Bob wins.
Upvotes: 5
Reputation: 17173
Here is some code that builds the graph for you, but requires you to call reverse() on the graph, create a source node connecting to all nodes in the base, flow back to source seeing if there is a way alice wins.
input_ = """2
3
1 3 2
5
5 3 2 1 4""".splitlines()
perms = [map(int,perm.split()) for perm in input_ if len(perm)>1]
"[['1', '3', '2'], ['5', '3', '2', '1', '4']]"
if networkx is None:
import networkx
from itertools import combinations
def build_graph(perm):
base = set()
G = networkx.DiGraph()
for r in range(1,len(perm)+1):
for combo in combinations(perm,r):
combo = list(combo)
if combo == sorted(combo):
base.add(tuple(combo))
continue
for i in range(r):
G.add_edge(tuple(combo),tuple(combo[:i]+combo[i+1:])) #you may want to reverse the graph later to point from base to source.
return G,base
def solve(G,base):
#dfs,
pass
for perm in perms:
G,base = build_graph(perms[0])
print solve(G,base)
Upvotes: 0
Reputation: 133
To me (using almost your own words):
If he/she is able to make it strictly increasing on the first move he/she wins (Trivial case) otherwise the the winner is decided by the number of elements in that sequence.
Take your second case as example.
I think that the graph solution is fine but it forgets that the players play in a optimal way. So don't need to check all the different path since some of them will derive from a non-optimal choice.
Upvotes: -2
Reputation: 17173
This game can be solved recursively.
Each time alice takes her first pick and picks i, subtract 1 from all the remaining numbers that are larger than i. Now we have the same game but with the numbers 1 to N-1
lets say your sequence is
1,3,5,4,2
on her first move, Alice can pick any number. case1: she picks 1, alice can win if bob cant win with 3,5,4,2 (equivalently 2,4,3,1)
case2: she picks 3 first. Alice can win if bob cant win with 1,5,4,2 (equivalently 1,4,3,2)
case3: she picks 5 first. Alice can win if bob cant win with 1,3,4,2
you get the idea.
So you can make a recursive function to work out the solution for a size N permutation all by using size N-1 permutations for each possible first guess. the base case for the recursion is when you have an in-order sequence.
Each step of the recursion, the person tries all possibilities and picks any that makes them win.
Because there are many combinations of moves that can get down to the same sequence, the recursion has overlapping sub problems. This means we can use dynamic programming, or simply "memoize" our function, greatly increasing efficiency.
For further speedup one may use symmetry in the permutations, as many groups of permutations are equivalent, such as the reverse of one permutation would yield the same result.
Good luck.
Upvotes: 2
Reputation: 70929
This is a typical game problem. You have 2^15 possible positions which denote which are the remaining numbers. From the number of the remaining numbers you can derive whose turn it is. So now you have a graph that is defined in the following manner - the vertices are the possible sets of remaining numbers and there is an edge connecting two vertices u and v iff there is a move that changes set u to set v(i.e. set v has exactly one number less).
Now you already pointed out for which positions you know who is the winner straight away - the ones that represent increasing sequences of numbers this positions are marked as loosing. For all other positions you determine if they are wining or loosing in the following manner: a position is winning iff there is an edge connecting it to a loosing position. So all that is left is to something like a dfs with memoization and you can determine which positions are winning and which are loosing. As the graph is relatively small (2^15 vertices) this solution should be fast enough.
Hope this helps.
Upvotes: 9