给定一张 行 列的棋盘,每个格子可能是空的或包含一个标志,标志有 和 两种。
如果有三个相同的标志排列在一行或一列上的三个连续的位置,则称这个棋盘是一个 胜局,
否则称其为 平局。例如,上图第一行的局面都是胜局,而第二行的局面都是平局。
在一次操作中,你可以将一个 改成 ,或将一个 改成 。
设棋盘中标志的总数为 ,你需要用不超过
次操作把给定的局面变成平局。。
看到 和 子棋就很容易想到抽屉原理,那么考虑把所有格子 按照 分成三类。
不难发现,若 ,那么只要所有格子满足以下条件:
- 满足 的有棋子的格子都为 ;
- 满足 的有棋子的格子都为 ;
就可以使局面为平局,因为同一行上或同一列上相邻三个棋子的分类一定不同。
那么枚举 即可,不难发现有 种情况,所有情况的操作总次数为 。那么由于抽屉原理 ,所以一定有一种情况合法。
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
const int S=305;
int n;
char a[S][S],b[S][S];
inline int work(int tp1,int tp2)
{
int tot=0;
for(int i=1;i<=n;i++) for(int j=1;j<=n+1;j++) b[i][j]=a[i][j];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int id=(i+j)%3;
if(a[i][j]=='X'&&id==tp1) tot++,b[i][j]='O';
if(a[i][j]=='O'&&id==tp2) tot++,b[i][j]='X';
}
}
return tot;
}
inline void print()
{
for(int i=1;i<=n;i++) printf("%s\n",b[i]+1);
}
inline void slove()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%s",a[i]+1);
int k=0;
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) k+=a[i][j]!='.';
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
if(i==j) continue;
if(work(i,j)<=k/3)
{
print();
return;
}
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T-->0) slove();
return 0;
}