HDU-6886 Tic-Tac-Toe-Nim(2020HDU多校第十场T10)

HDU-6886 Tic-Tac-Toe-Nim(2020HDU多校第十场T10)

正如题目名字,这是一个nim游戏

观察题目条件,前两次操作一定会清空两个位置,那么考虑后面得到的状态是否先手必胜即可

对于这两个位置,发现只有两种情况

两个位置共线

此时先手者直接选择同线的另一个即可,必胜

两个位置不共线

此时还剩下一个位置与这两个空位均不共线,其他6个位置均共线

考虑可能存在的结束情况:

1.6个位置中有一个被清空,则下一个人直接清空共线的另一个位置必胜

2.不共线的位置被清空,不影响结局

考虑把这个问题转化为普通的Nim游戏

可以认为如果那6个位置均为1时游戏必败,而不共线的一个位置随意

则转化为 六个共线位置的值-1不共线位置的值 形成的普通Nim游戏,根据常识,直接异或判断即可

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
int rd(){
    int IO,s=0;
    while(!isdigit(IO=getchar()));
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return s;
}

int a[4][4];
int Check(){ // 判断是否必胜
    rep(i,1,3) rep(j,1,3) if(a[i][j]) {
        int fl=1;
        rep(k,1,3) if(j!=k && !a[i][k]) fl=0;
        rep(k,1,3) if(k!=i && !a[k][j]) fl=0;
        if(!fl) continue;
        int x=a[i][j],ans=0;
        a[i][j]=0;
        rep(i,1,3) rep(j,1,3) if(a[i][j]) ans^=a[i][j]-1; // 共线位置
        ans^=x,a[i][j]=x; // 不共线位置
        return ans;
    }
    return '?';
}

int main(){
    rep(kase,1,rd()) {
        rep(i,1,3) rep(j,1,3) a[i][j]=rd();
        int ans=0;
        rep(i,1,3) rep(j,1,3) {
            int t=a[i][j];
            a[i][j]=0;
            int fl=0;
            rep(x,1,3) rep(y,1,3) { // 枚举两次初始操作,注意两次操作不共线!
                if(x==i || y==j) continue;
                int t=a[x][y];
                a[x][y]=0;
                if(!Check()) fl=1;
                a[x][y]=t;
            }
            if(!fl) ans++;
            a[i][j]=t;
        }
        printf("%d
",ans);
    }
}

原文地址:https://www.cnblogs.com/chasedeath/p/13537103.html