CF538D 题解
本文最后更新于 2025年1月2日 晚上
题目描述
题目较复杂,完整翻译在这里。
给定一个 $n\times n$ 的棋盘,其中 $1\le n\le50$。棋盘上有一些棋子。已知棋盘上每个空位是否被攻击。现在要求你还原棋子的移动规则,或判断是否有误。
解题思路
这里很多人会绕进一个坑,就是我们根本不知道某个棋子会按哪种方式走哪几步。
观察题目,我们只需要找出某一种移动方式并输出即可。不妨让所有棋子一步到位,走一步完成现有棋局情况。正确性稍后证明。
再次观察题目,注意到棋子只有一种,即棋盘上出现的所有棋子都需要满足同一种移动规律。这也就意味着,对于棋盘上的所有棋子,可以移动到的位置是交起来的,而不可移动到的位置是并起来的。
也就是说,与其判断某个棋子可以攻击哪里,不如判断它不能攻击哪里。既然一些位置不能被攻击,那棋子在这个方向上一定是不可行的。我们只需要将不可行的全部排除,再检查可行范围是否矛盾即可。
观察数据范围,$n\le 50$,考虑 $O(n^4)$ 暴力。
遍历每个棋子和每个空位,将棋子在空位方向上的移动规则标记为不可移动,剩下全部标记为可移动。这样构造出来的移动规则就是可能的答案。
最后按照这个移动方案,检查所有应受攻击位置是否能受到攻击即可。
正确性证明
我们按照上面的方式生成移动规则,生成的位置一定是满的 (即下文所述“最大化”)。这也就意味着,在一步范围之内,所有可能被攻击的位置一定都能攻击。
接下来我们考虑这样一个问题:为什么走一步不能走出来的棋局,走多步也不可能走出来。
由于攻击范围是 $2n-1\times2n-1$ 的,一个棋子在整个棋局内的目标的行为都是确定的。由于生成的规则是满的,有解情况下,两步棋能到的一步棋都可以到。
无解情况
我们所选择的移动集是最大化的,这意味着如果再添加其他的移动,将会导致棋盘不再正确。
我们让所有棋子执行所有剩下的、未被标记为不可能的移动,并重新创建与原始相同位置的棋盘。
- 如果某个格子在初始状态下没有被攻击,那么在新生成的棋盘中它也不会被攻击;
- 某些之前被攻击的格子在新棋盘中未被攻击,那么原棋盘就不能构成任何合法的移动方式,因为移动集已最大化,添加一个新的攻击方向会导致其它棋子出现问题。
算法步骤
设原棋盘为 $n\times n$ 的矩阵 $A$,转移规律为 $2n-1\times2n-1$ 的矩阵 $D$。
$0$ 表示 .
,不可移动到/不可被攻击;$1$ 表示 x
,可以移动到/可以被攻击;$2$ 表示 o
,棋子所在位置。
- 将每一种移动标记为可能,$D_{x,y}=1$。
- 对每一个棋子 $(X_i,Y_i)$ 和每一个不可被攻击的位置 $(x_j,y_j)$,可以得到棋子不具有移动规律 $\begin{cases}X_i\leftarrow X_i+(x_j-X_i)\Y_i\leftarrow Y_i+(y_j-Y_i)\end{cases}$。所以转移矩阵中 $D_{x_j-X_i,y_j-Y_i}=0$。
- $D_{n,n}\leftarrow2$,表示移动规则的中心位置是自身棋子。
- 根据移动规则还原棋局 $T$:$\forall A_{x,y}=2,\ D_{i,j}=1,\ x+i,y+j\in[1,n],\ T_{x+i,y+j}\leftarrow1$。
如果对于任意位置,原棋局中的受攻击情况与还原棋局不同,则说明无解。
代码实现
AC 1.21MB 77ms
1 |
|
总结
本体难点:理解“最大化”移动规则的创建方式和特殊性质。