Tic-Tac-Toe-Nim

题目链接

Tic-Tac-Toe-Nim

井字棋,\(A\)\(B\) 轮流取,可以取一个格子里的一些石子,先取完一行或者一列获胜。
要求 \(A\)\(B\) 第一次取的时候必须取完一个格子。
\(A\) 能必胜的格子数

解题思路

博弈论,nim游戏

枚举 \(A\) 第一次选择的格子数,则 \(B\) 不能选择与 \(A\) 同行或同列的格子,因为如果 \(B\) 选择后 \(A\) 可以选择某一行或列的最后一个非空格子,这是 \(B\) 只有 \(4\) 个格子可选,其中一个格子可任选,另外 \(6\) 个格子当其中有一个格子为空时即能决定胜负,即如果先手最后面对 \(6\) 个格子全为 \(1\),任选格子为 \(0\) 时必败,等价于先对 \(6\) 个格子减一和另外一个格子的 \(nim\) 游戏,如果异或和为 \(0\),先手必败,即一开始时后手可以选择该格子使后手必败,否则如果这样所有的 \(4\) 个格子都不能使先手必败则先手必胜

  • 时间复杂度:\(O(81\times T)\)

代码

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

int t,a[5][5],res,x;
int main()
{
    for(read(t);t;t--)
    {
    	x=0;
    	for(int i=1;i<=3;i++)
    		for(int j=1;j<=3;j++)
    		{
    			read(a[i][j]);
    			x^=(a[i][j]-1);
    		}
    	res=0;
    	for(int i=1;i<=3;i++)
    		for(int j=1;j<=3;j++)
    		{
    			bool f=true;
    			for(int k=1;k<=3&&f;k++)
    				for(int p=1;p<=3;p++)
    				{
    					if(k==i||p==j)continue;
    					if((x^(a[i][j]-1)^(a[k][p]-1)^(a[6-i-k][6-j-p]-1)^(a[6-i-k][6-j-p]))==0)
    					{
    						f=false;
    						break;
    					}
    				}
    			res+=f;
    		}
    	printf("%d\n",res);
    }	
    return 0;
}
posted @ 2022-04-28 21:11  zyy2001  阅读(45)  评论(0编辑  收藏  举报