The funny stone game is coming. There are n piles of stones, numbered with 0, 1, 2,..., n - 1. Two persons pick stones in turn. In every turn, each person selects three piles of stones numbered i, j, k (i < j, j k and at least one stone left in pile i). Then, the person gets one stone out of pile i, and put one stone into pile j and pile k respectively. (Note: if j = k, it will be the same as putting two stones into pilej). One will fail if he can't pick stones according to the rule.
David is the player who first picks stones and he hopes to win the game. Can you write a program to help him?
The number of piles, n, does not exceed 23. The number of stones in each pile does not exceed 1000. Suppose the opponent player is very smart and he will follow the optimized strategy to pick stones.
Input
Input contains several cases. Each case has two lines. The first line contains a positive integer n ( 1 n 23) indicating the number of piles of stones. The second line contains n non-negative integers separated by blanks, S0,...Sn-1 ( 0 Si 1000), indicating the number of stones in pile 0 to pile n - 1respectively.
The last case is followed by a line containing a zero.
Output
For each case, output a line in the format ``Game t: i j k". t is the case number. i, j and k indicates which three piles David shall select at the first step if he wants to win. If there are multiple groups of i, jand k, output the group with the minimized lexicographic order. If there are no strategies to win the game,i, j and k are equal to -1.
Sample Input
4 1 0 1 100 3 1 0 5 2 2 1 0
Sample Output
Game 1: 0 2 3 Game 2: 0 1 1 Game 3: -1 -1 -1
题意:
给你n堆石子,从左到右编号为0~n-1,并且告诉你每堆石子的个数(注意有的堆石子个数可能为0,但是还是为一个堆).两个人轮流操作,当某人无法执行操作时输。
每次操作为选择三个数i,j,k满足(i<j<=k)并且第i堆石子个数不能为0,然后拿走i堆一个石子,并且向j,k堆各添加一个石子。注意:j,k可以是相同的。
分析:
这个游戏满足ICG游戏,我们尝试使用SG函数来求解。
该问题如果把一个堆当作一个游戏显然不容易分析。因为再一次操作中被操作堆有的是被拿走石子,有的是添加石子。所以在这个游戏中我们把一个石子当作一个游戏,每次操作可以看作把该石子右移并分身。那么我们先将n堆序号重新编号为n-1,n-2,......1,0则最右堆为0号堆。那么一个石子被移动到0号堆就不能继续向后面移动了。所以在i号堆的某个石子的后继状态为sg[j]^sg[k]。所以 sg[i] = mex(sg[j]^sg[k]) 满足 i>j>=k。
每个堆的石子都是一样的,所以sg值都是sg[index]。index是该队的序号,所以只需要将所有石子的sg值异或起来就是整个游戏的sg值。这里需要注意一下:因为一个堆的每个石子sg值都是一样的。如果这个堆有偶数个石子。显然这个堆的所有石子的异或值为0,如果这个堆的石子个数是奇数,显然这个堆的所有石子的异或值为sg[index]。
代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 200;
int visit[maxn],sg[maxn];
void init()
{
for(int i = 0; i <= 23 ; i ++)
{
memset(visit,0,sizeof(visit));
for(int j = 0 ; j < i ; j ++)
{
for(int k = j ; k < i; k ++)
{
visit[sg[j]^sg[k]] = 1;
}
}
for(int j = 0 ; j < maxn ; j ++)
if(!visit[j])
{
sg[i] = j;
break;
}
}
}
int a[30];
int main()
{
init();
int n,step,_case = 0;
while(cin >>n)
{
if(n == 0)break;
printf("Game %d: ",++_case);
int ans = 0;
for(int i = 0 ; i < n ; i ++)
{
scanf("%d",&a[i]);
if(a[i]&1) ans ^= sg[n-i-1];
}
if(ans == 0)
printf("-1 -1 -1\n");
else
{
int flag = 0;
for(int i = 0 ; i < n ; i ++)
{
if(a[i] == 0) continue;
for(int j = i+1 ; j < n ; j ++)
{
for(int k = j ; k < n ; k ++)
{
if((ans^sg[n-i-1]^sg[n-j-1]^sg[n-k-1]) == 0) //只需要找到字典序最小的操作使得当前局面的sg值为0,即可使得必胜。
{
flag = 1;
printf("%d %d %d\n",i,j,k);
break;
}
}
if(flag)break;
}
if(flag)break;
}
}
}
return 0;
}