博弈——Treblecross

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

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


题意:

给一个字符串,两人轮流把'.'换成'X',谁先使局面变成三个连续的'X'谁赢 ,如果存在赢的走法,输出所有赢的走法的第一步,如果必输输出0

思路:

很明显一个'X'的左边两个格子和右边两个格子都是不能下的,否则对手会赢。那么将这个字符串分区来异或各区间的sg值即可


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <stack>
#define INF 0x3f3f3f3f
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int maxn=220;
int sg[maxn];
int pos;
int n;
char s[maxn];
int ans[maxn];
bool win()     //判断当前局势是否已经出现三个连续'X'
{
    for(int i=0; i<n-2; i++)
         if(s[i]=='X'&&s[i+1]=='X'&&s[i+2]=='X')
            return true;
    return false;
}
int getsg(int x)
{
    if(sg[x]!=-1)
        return sg[x];
    if(x==0)
        return sg[x]=0;
    bool vis[maxn]={false};
    for(int i=1; i<=x; i++)
        vis[getsg(max(0, i-3))^getsg(max(0, x-i-2))]=true;  //如果在连续x个空格子里放一个'X'那么其左右两边各两个格子都不能放'X'
    for(int i=0; ; i++)
        if(!vis[i])
            return sg[x]=i;
}
bool towin()
{
    for(int i=0; i<n; i++)
    {
        if(s[i]=='X')
            continue;
        s[i]='X';
        if(win())   //如果对手可以赢
        {
            s[i]='.';
            return false;
        }
        s[i]='.';
    }
    int tag=0;
    int cnt=0;
    for(int i=0; i<n; i++)
    {
        if(s[i]=='X'||(i>=1&&s[i-1]=='X')||(i>=2&&s[i-2]=='X')||(i+1<n&&s[i+1]=='X')||(i+2<n&&s[i+2]=='X')) //判断这个格子是否能走
        {
            tag^=getsg(cnt);
            cnt=0;
        }
        else
            cnt++;
    }
    tag^=getsg(cnt);
    return tag==0;
}
void solve()
{
    pos=0;
    scanf("%s", s);
    n=strlen(s);
    for(int i=0; i<n; i++)
    {
        if(s[i]=='X')
            continue;
        s[i]='X';  //如果这一个不是'X',将这一格变成'X'看是否会赢
        if(win()||towin())    //如果能赢,就存下来
            ans[pos++]=i+1;
        s[i]='.';      //还原
    }
}
int main()
{
    int t;
    scanf("%d", &t);
    for(int cas=1; cas<=t; cas++)
    {
        memset(sg, -1, sizeof(sg));
        solve();
        if(pos==0)
            printf("Case %d: 0\n", cas);
        else
        {
            printf("Case %d: %d", cas, ans[0]);
            for(int i=1; i<pos; i++)
                printf(" %d", ans[i]);
            printf("\n");
        }
    }
    return 0;
}







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值