[CF1450C]Errich-Tac-Toe

这篇博客讨论了一种解决棋盘游戏胜利策略的问题,重点在于如何通过分析横竖连续三格涉及的对角线来确定X和O的获胜条件。作者提出了一种优化的算法,通过枚举对角线类别来找到最少的操作次数,使得双方无法形成胜利局面,复杂度为O(n^2)。文章包含了详细的思路解析和C++代码实现。
摘要由CSDN通过智能技术生成

题目

传送门 to CF

思路

我吐了,这道题做了 1 h 1h 1h 也做不出来。真的很 t r i c k y \rm tricky tricky 啊……

考虑这样一个事实:任意一个横着或竖着的连续三格,都涉及到了 三条对角线(左下到右上)。对角线的编号是 x + y x+y x+y,将它们按照模三的余数分类。如果在某一个类中,根本没有 X 出现过,那么就不会形成 X 的胜利局面,O 也是同理。

于是问题转化为,给 XO 分别选择一个不能出现类 a , b    ( a ≠ b ) a,b\;(a\ne b) a,b(a=b),操作次数就是 c n t a ( X ) + c n t b ( O ) cnt_{a}(X)+cnt_b(O) cnta(X)+cntb(O) 。只需要它不超过 ⌊ k 3 ⌋ \lfloor{k\over 3}\rfloor 3k

这样的 a , b a,b a,b 一定存在。若 a , b a,b a,b 可以同时取到最小值(让 c n t a ( X ) cnt_a(X) cnta(X) 最小)就已经成立了,因为二者都不超过总数的 1 3 1\over 3 31 。否则,考虑这三个组合: c n t ( X ) cnt(X) cnt(X) 的最小与 c n t ( O ) cnt(O) cnt(O) 的次小; c n t ( X ) cnt(X) cnt(X) 的次小与 c n t ( O ) cnt(O) cnt(O) 的最小; c n t ( X ) cnt(X) cnt(X) 的最大与 c n t ( O ) cnt(O) cnt(O) 的最大。前两个组合都合法,而且都严格小于第三个组合。这三个组合的和显然是 k k k,如果前两个都大于 ⌊ k 3 ⌋ \lfloor{k\over 3}\rfloor 3k,那么第三个也大于 ⌊ k 3 ⌋ \lfloor{k\over 3}\rfloor 3k,矛盾。

但是这样实现挺麻烦,不如直接枚举 a , b a,b a,b 找最小的一个。反正有解嘛。复杂度 O ( n 2 ) \mathcal O(n^2) O(n2)

代码

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long int_;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
inline int ABS(const int &x){
	return x < 0 ? -x : x;
}

const int MaxN = 305;
char maze[MaxN][MaxN];
int cnt[300][3];

int main(){
	for(int T=readint(); T; --T){
		int n = readint();
		rep(j,0,2) // clear
			cnt['X'][j] = cnt['O'][j] = 0;
		rep(i,1,n){
			scanf("%s",maze[i]+1);
			rep(j,1,n) ++ cnt[
				int(maze[i][j])][(i+j)%3];
		}
		int a = 0, b = 0, mn = n*n;
		rep(i,0,2) rep(j,0,2)
			if(i != j && cnt['X'][i]+cnt['O'][j] < mn){
				mn = cnt['X'][i]+cnt['O'][j];
				a = i, b = j;
			}
		rep(i,1,n){
			rep(j,1,n)
				if(maze[i][j] == 'X')
					if((i+j)%3 == a)
						putchar('O');
					else putchar('X');
				else if(maze[i][j] == 'O')
					if((i+j)%3 == b)
						putchar('X');
					else putchar('O');
				else putchar('.');
			putchar('\n');
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值