36 博弈sg值

G - Treblecross

LightOJ - 1229

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

Given the current state of the game, you are to determine if the current player to move can win the game assuming both players play optimally.

Consider the game where the board size is 5 cells. If the first player puts an X at position three (in the middle) so the state becomes ..X.., he will win the game as no matter where the other player puts 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 win the game by putting the X in the opposite corner (for instance, after the second players move the state might be .X..X). This will force the first player to put an X in a position so the second player wins in the next move.

Input

Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case starts with a line containing a string denoting the current status of the game. The string will only contain the characters '.' and 'X'. The length of the string (the size of the board) will be between 3 and 200 characters, inclusive. No state will contain three X in a row.

Output

For each case, print the case number and the positions on the board, where the player to move may put an X and win the game. The positions should be separated by a single space, and be in increasing order. The leftmost position on the board is 1. If there is no such position print 0.

Sample Input

扫描二维码关注公众号,回复: 3291358 查看本文章

4

.....

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

.X.X...X

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

Sample Output

Case 1: 3

Case 2: 0

Case 3: 3

Case 4: 5 6 13 14

sg值是博弈的灵魂如果找到当前状态的sg值就可以得到相应的答案;

1,后继状态的分析如果是当前的状态只能转换的一种状态就是每个单独的存在(传统的取石子游戏);

但是如果是将一堆石子分成两部分的话,就是分完后的两堆石子的异或值作为这堆石子的一个后继状态;

2,状态的选择就是我们一般选择可以进行任意操作的状态作为我们要的相互转移的状态,并且两个状态除了大小之外,其他的条件应该是一样的,这道题目的状态我们选择的是可以进行任意操作的长度,(换一句话说边界的<=2的距离内不能有X,否则在边界上放点的话就是必输了,它的后继状态分析就是类似的如果我们在下面的长度上放X)

我们要操作的长度 :。。。。。。。。。。

                                                x

这样的话就被分成了两个更小的问题,左边是4,右边是5(对吗??)我们在之前说了,后继状态跟前面的状态除了规模应该是一样的,就是随便放所以左边(5-3),右边是(10-5-2),这是他的两个后继状态,同时存在,所以sg[5-2]^sg[10-5-2]才是他的一个后继状态,因为此时的长度上才是可以随便放的,所以,在这一段上可以放的每一个点,标记一下他们后继状态的sg值就是可一个求出当前状态的sg值了,其实sg值的问题就是将问题划分成更小的子问题的过程,就是不断递归的过程,尼姆博弈的sg值一般是用暴力跑出来的这样的话因为后来的状态在前面的都可以找到所以不用递归,如果是用递归的话也是可以的;

#include <bits/stdc++.h>
using namespace std;
const int Max = 5e2+10;
typedef long long ll;
#define rep(i,s,n) for(ll i=s;i<=n;i++)
#define per(i,n,s) for(ll i=n;i>=s;i--)
int sg[Max];
char ch[Max];
int a[Max],num;
int getsg(int x){
   if(x<0) return 0;
   if(sg[x]!=-1) return sg[x];
   bool visited[Max];
   rep(i,0,Max-10) visited[i]=false;
   rep(i,1,x){
     visited[getsg(i-3)^getsg(x-i-2)]=1;
   }
   for(int i=0;;i++){
    if(!visited[i]) return sg[x]=i;
   }
}
bool judge(int x){
    if(ch[x]=='X') return 0;
    int len=strlen(ch);
    char tmp[Max];
    rep(i,0,len-1) tmp[i]=ch[i];
    tmp[x]='X';
    for(int i=0;i<len;i++){
        if(i+1<=len-1&&i+2<=len-1&&tmp[i]=='X'&&tmp[i+1]=='X'&&tmp[i+2]=='X')  return 1;
    }
    for(int i=0;i<len;i++){
        if(tmp[i]=='X'&&i+1<=len-1&&tmp[i+1]=='X') return 0;
        if(tmp[i]=='X'&&i+2<=len-1&&tmp[i+2]=='X') return 0;
    }
    int flag=0,w=2,cnt=-1;
    per(i,len-1,0){
       if(tmp[i]=='X'){
        cnt=i;
        break;
       }
    }
    int i,j;
    int ans=0;
    for(i=0;i<len;i++){
        if(i>cnt) w=0;
        if(tmp[i]=='X'){
            flag=2;
            continue;
        }
        for(j=i;j<len&&tmp[j]=='.';j++);
        ans^=getsg(j-i-flag-w);
        i=j-1;
    }
    if(ans) return 0;
    return 1;
}
int main(){
   int t,ca=1;
   scanf("%d",&t);
   rep(i,1,Max-10) sg[i]=-1;
   while(t--){
    num=0;
    scanf("%s",ch);
    getchar ();
    int len=strlen(ch);
    rep(i,0,len-1){
        if(judge(i)) a[num++]=i+1;
    }
    printf("Case %d: ",ca++);
    if(num==0){
       printf("0\n")   ;
    }
    else {
        rep(i,0,num-1){
           printf("%d%c",a[i],(i==num-1)?'\n':' ');
        }
    }
   }
   return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39792342/article/details/82799142
36