UVA10561 Treblecross 组合游戏/SG定理

时间:2021-03-24 15:11:25

Treblecross is a two player gamewhere the goal is to get three X in a row on a one-dimensional board. At the startof the game all cells in the board is empty. In each turn a player puts a X in an empty cell, and if that results in there beingthree X next to each other, that player wins.

Given the current state of the game, you are todetermine if the player to move can win the game assuming both players playperfectly. If so, you should also print all moves that will eventually lead toa win.

Consider the game where the board size is 5cells. If the first player puts a X at position three (in the middle) so thestate becomes ..X.., he will win the game as no matter where the other playerputs his X, the first player can get three X in a row. If, on the other hand,the first player puts the X in any other position, the second player will winthe game by putting the X in the opposite corner (for instance, after thesecond player moves the state might be .X..X). This will force the first playerto put an X in a position so the second player wins in the next move.

Input

The input begins with an integer N ( N< 100),the number of states that will follow. Each state is represented by a string ona line by itself. The string will only contain the characters '.' and 'X'. Thelength of the string (the size of the board) will be between 3 and 200characters, inclusive. No state will contain three X in a row.

Output

For each case, first output WINNING or LOSING depending onif the player to move will win or lose the game. On the next line, output inincreasing order all positions on the board where the player to move may put anX and win the game. The positions should be separated by a blank, and be inincreasing order. The leftmost position on the board is 1.

  SampleInput                                                   Outputfor Sample Input

4

.....

X.....X..X.............X....X..X

.X.X...X

...............................................

WINNING

3

LOSING

 

WINNING

3

WINNING

1 12 15 17 20 24 28 31 33 36 47

 

题意:给定一个串,上面有'X'和'.',可以在'.'的位置放X,谁先放出3个'X'就赢了,求先手必胜的策略

题解:SG函数,每个串要是上面有一个X,周围的4个位置就是禁区了(放下去必败),所以可以以X分为几个子游戏去求SG函数的异或和进行判断,至于求策略,就是枚举每个位置就可以了

#include<bits/stdc++.h>
#define N 250
#define mes(x) memset(x, 0, sizeof(x));
#define ll __int64
const long long mod = 1e9+;
const int MAX = 0x7ffffff;
using namespace std;
int SG[N], dir[N], a[N], l;
char s[N];
int f(){
int num, i, ans;
for(ans=num=i=;i<=l;i++)
if(!a[i]) num++;
else{
ans ^= SG[num];
num = ;
}
return ans;
}
void getsg(){
int n, x, j;
SG[] = ;
SG[] = SG[] = SG[] = ;
for(n=;n<=;n++){
mes(dir);
for(x=n-;x<=n-;x++)
if(x>=) dir[SG[x]] = ;
for(x=;n--x>=;x++)
dir[SG[x]^SG[n--x]] = ;
for(j=;;j++){
if(!dir[j]){
SG[n] = j;
break;
}
}
}
}
int main()
{
int T, i, flag, j;
getsg();
scanf("%d", &T);
while(T--){
scanf("%s", s);
l = strlen(s);
if(strstr(s,"X.X")||strstr(s, "XX")){
mes(dir);
printf("WINNING\n");
for(i=;i<l-;i++){
if(s[i] == 'X'&&s[i+] == 'X') dir[i+] = ;
if(s[i] == 'X'&&s[i+] == 'X'){
dir[i+] = ;
if(i >= )
dir[i-] = ;
}
}
if(s[l-] == 'X'&& s[l-] == 'X')
dir[l-] = ;
for(flag=i=;i<;i++)
if(dir[i]){
printf("%s%d", flag?" ":"", i+);
flag = ;
}
printf("\n");
}
else{
mes(dir);
for(i=;i<l;i++)
if(s[i] == 'X')
for(j=i-;j<=i+;j++)
if(j<l&&j>=) dir[j] = ;
memcpy(a, dir, sizeof(a));
a[l] = ;
if(!f()){
printf("LOSING\n\n");
continue;
}
printf("WINNING\n");
for(flag=,i=;i<l;i++){
memcpy(a, dir, sizeof(a));
a[l] = ;
if(!dir[i]){
for(j=i-;j<=i+;j++)
if(j<l&&j>=) a[j] = ;
if(!f()){
printf("%s%d", flag?"":" ", i+);
flag = ;
}
}
}
printf("\n");
}
}
}