uva10561 - Treblecross SG定理

Treblecross
Input:
Standard Input

Output: Standard Output

Time Limit: 4 Seconds

 

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

 

  N个格子排成一行,里面有些是X,两个人轮流往空的地方放X,如果出现连续3个X,那个人获胜,。如果能获胜,输出必胜方案的第一步。

  我最开始想的是递归子状态的SG,可能是因为X位置问题,不能表示状态。。

  其实完全可以先求出所有地方都是空的SG,sg[n]表示连续连续n个空的SG值。那样对于某种状态,只要在把它能放X的段的SG全部异或就行了。

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<algorithm>
#define eps 1e-9
#define MAXN 210
#define MAXM 110
#define MOD 100000007
typedef long long LL;
using namespace std;
int T,sg[MAXN],g[MAXN];
char str[MAXN];
vector<int> ans;
int win(){
    int L=strlen(str);
    for(int i=0;i<L-2;i++) if(str[i]=='X'&&str[i+1]=='X'&&str[i+2]=='X') return 0;
    int no[MAXN]={0};
    for(int i=0;i<L;i++) if(str[i]=='X'){
        for(int d=-2;d<=2;d++) if(i+d>=0&&i+d<L){
            if(d&&str[i+d]=='X') return 1;  //1不一定表示这个状态的SG,SG有可能更大。反正这道题只要有SG大于0就可以
            no[i+d]=1;
        }
    }
    no[L]=1;
    int start=-1,SG=0;
    for(int i=0;i<=L;i++){
        if(start<0&&!no[i]) start=i;
        if(no[i]){
            if(start>=0) SG^=sg[i-start];
            start=-1;
        }
    }
    return SG;
}
int mex(vector<int>& s){
    if(s.empty()) return 0;
    sort(s.begin(),s.end());
    if(s[0]) return 0;
    int L=s.size();
    for(int i=1;i<L;i++) if(s[i]>s[i-1]+1) return s[i-1]+1;
    return s[L-1]+1;
}
void init(){
    sg[0]=0;
    sg[1]=sg[2]=sg[3]=1;
    for(int i=4;i<MAXN;i++){
        vector<int> s;
        s.push_back(sg[i-3]);
        s.push_back(sg[i-4]);
        if(i>=5) s.push_back(sg[i-5]);
        for(int j=3;j<i-3;j++) s.push_back(sg[j-2]^sg[i-j-3]);
        sg[i]=mex(s);
    }
}
int main(){
    freopen("in.txt","r",stdin);
    init();
    scanf("%d",&T);
    while(T--){
        scanf("%s",str);
        ans.clear();
        int sum=win();
        if(!win()){
            printf("LOSING\n\n");
            continue;
        }
        for(int i=0;i<strlen(str);i++) if(str[i]=='.'){
            str[i]='X';
            if(!win()) ans.push_back(i+1);
            str[i]='.';
        }
        int L=ans.size();
        if(L){
            printf("WINNING\n");
            int first=1;
            for(int i=0;i<L;i++){
                if(first) first=0;
                else printf(" ");
                printf("%d",ans[i]);
            }
            puts("");
        }
        else printf("LOSING\n");
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值