uva10561 Treblecross

137 篇文章 0 订阅

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 is empty. In each turn a player puts a
X ’ in an
empty cell, and if that results in there being three X ' next to
each other, that player wins. Given the current state of the game, you
are to determine if the player to move can win the game assuming both
players play perfectly. If so, you should also print all moves that
will eventually lead to a win. Consider the game where the board size
is 5 cells. If the rst player puts a
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 rst player can get
three X ' in a row. If, on the other hand, the rst 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 player moves the state might be
.X..X ‘). This will force the
rst player to 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 on a line by itself. 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, rst output
WINNING ' or
LOSING ’ depending on if the player to move will win or
lose the game. On the next line, output in increasing order all
positions on the board where the player to move may put an X and win
the game. The positions should be separated by a blank, and be in
increasing order. The leftmost position on the board is 1.

首先判断能否一步取胜,如果能直接输出。
否则可以发现,每个格子左右共五个位置都是不能放的,这样棋盘就被分成了若干个独立的区域,每次可以在某个区域落子。预处理出任意长度格子的SG函数,求异或和。输出方案只需要枚举可以落子的地方,检验新的SG和。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200;
char s[210];
int g[210],a[210],vis[210],n;
void make()
{
    int i,j,x;
    g[1]=g[2]=1;
    for (i=3;i<=maxn;i++)
    {
        memset(vis,0,sizeof(vis));
        for (j=1;j*2<=i+1;j++)
        {
            x=g[i-j-2];
            if (j>3) x^=g[j-3];
            vis[x]=1;
        }
        for (j=0;;j++)
            if (!vis[j])
            {
                g[i]=j;
                break;
            }
    }
}
void init()
{
    int i;
    scanf("%s",s+1);
    n=strlen(s+1);
    for (i=1;i<=n;i++)
        a[i]=(s[i]=='X');
}
bool ok(int p)
{
    if (a[p]) return 0;
    if (p<=n-2&&a[p+1]&&a[p+2]) return 1;
    if (p>=2&&p<=n-1&&a[p-1]&&a[p+1]) return 1;
    if (p>=3&&a[p-2]&&a[p-1]) return 1;
    return 0;
}
bool ban(int p)
{
    return a[p]||
        (p>=2&&a[p-1])||
        (p>=3&&a[p-2])||
        (p<=n-1&&a[p+1])||
        (p<=n-2&&a[p+2]);
}
int calc()
{
    int i,now=0,ans=0;
    for (i=1;i<=n;i++)
        if (ban(i))
        {
            ans^=g[now];
            now=0;
        }
        else
            now++;
    ans^=g[now];
    return ans;
}
void solve()
{
    int i,j,flag=0;
    for (i=1;i<=n;i++)
        if (ok(i))
        {
            printf("WINNING\n%d",i);
            for (j=i+1;j<=n;j++)
                if (ok(j))
                    printf(" %d",j);
            printf("\n");
            return;
        }

    if (calc())
    {
        printf("WINNING\n");
        for (i=1;i<=n;i++)
            if (!ban(i))
            {
                a[i]=1;
                if (!calc())
                {
                    if (flag) printf(" ");
                    flag=1;
                    printf("%d",i);
                }
                a[i]=0;
            }
        printf("\n");
    }
    else printf("LOSING\n\n");
}
int main()
{
    int T;
    make();
    scanf("%d",&T);
    while (T--)
    {
        init();
        solve();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值