AtCoder Beginner Contest 454
E - LRUD Moving
一、 题意解析
1. 核心任务
在一个 \(N \times N\) 的网格中,你需要找到一条从左上角 \((1, 1)\) 到右下角 \((N, N)\) 的路径。
2. 约束条件
- 必经点:除了一个给定的障碍点 \((A, B)\) 之外,必须访问网格中的每一个格子。
- 唯一性:每个格子只能访问一次(哈密顿路径)。
- 步数固定:总共移动 \(N^2 - 2\) 步。
- 移动规则:只能上下左右移动。
3. 输入输出
- 如果存在这样的路径,输出 "Yes" 并输出操作序列(U, D, L, R);
- 如果不存在,输出 "No"。
二、 算法思路
这道题的精髓在于棋盘染色理论和分层构造法。
1. 存在性判定(奇偶性检查)
我们将 \(N \times N\) 的格子进行黑白染色,规定 \((i, j)\) 的颜色由 \(i+j\) 的奇偶性决定。
格数规律:总共有 \(N^2\) 个格子。在 \(N\) 为偶数时,黑白格子各占一半(\(N^2/2\))。
路径规律:从 \((1, 1)\) 走到 \((N, N)\),如果访问了所有点,路径长度是 \(N^2 - 1\)。
本题关键:我们需要跳过一个点 \((A, B)\),路径长度变为\(N^2 - 2\)。
- \((1, 1)\) 和 \((N, N)\) 的坐标和都是偶数(同色),所以需要经过偶数步。所以当 \(N\) 为奇数的时候,\(N^2 - 2\) 为奇数,矛盾,所以输出No
- 要从一个颜色出发,走完除去一个点后的所有点并到达同色点。在上面的条件下,\(N\) 为偶数,\(N^2 - 1\) 为需要染色的方格个数 (因为跳过一个了),这个数为奇数,所以按照路径,偶奇偶奇......偶,所以被删除的点\((A, B)\),必然是奇数点,如果是偶数,那就输出No
- 因此,必须满足:\(N\) 是偶数,且 \(A+B\) 是奇数。否则直接输出 "No"。
2. 构造合法方案
将原问题 \(N \times N\) 逐步缩小,直到变成一个最简的 \(2 \times 2\) 核心区域。
步骤一:行缩减 (Horizontal Strips)
如果目标空洞 \((A, B)\) 不在前两行(\(A > 2\)),我们可以直接走完前两行:
- 路径:\((1,1) \to (1,N) \to (2,N) \to (2,1) \to (3,1)\)。
- 代码中的
s1字符串RRRRRDLLLLLLD对应的就是这一操作。通过这种方式,问题规模从 \(N \times N\) 缩减为 \((N-2) \times N\)。
步骤二:列缩减 (Vertical Strips)
在处理完行后,如果空洞 \((A, B)\) 不在前两列(\(B > 2\)),我们采用类似的逻辑走完最左边的两列:
- 路径:反复下右上右路径 ,\((1,1) \to (2,1) \to (2,2) \to (2,2) \to (3,1)\)。
- 这样将问题宽度减少 2,直到 \((A, B)\) 落在当前剩余区域的左上角 \(2 \times 2\) 范围内。
第三步:核心 \(2 \times 2\) 绕行
通过上述缩减,最终 \((A, B)\) 必然会落在一个 \(2 \times 2\) 或类似的局部区域内。此时:
- 如果 \((A, B)\) 在 \((1, 2)\),我们必须先走
D再走R绕开它。 - 否则,通常先走
R再走D。
第四步:后续填补
处理完包含 \((A, B)\) 的核心区域后,再用同样对称的逻辑(s3 和 s4)把右边和下面剩下的空间补齐。
代码
#include <bits/stdc++.h>
using namespace std;
void solve() {
int a, b, n, m, N;
cin >> n >> a >> b;
m = n;
N = n;
if (n % 2 == 1) {
cout << "No" << endl;
return;
}
if ((a + b) % 2 == 0) {
cout << "No" << endl;
return;
}
cout << "Yes" << endl;
// 1 .f(n,m,a,b)->f(n-2,m,a-2,b) RRRRRDLLLLLLD
int firstrow = 0;
string s1;
while (a > 2) {
n -= 2;
a -= 2;
firstrow++;
}
for (int i = 0; i < N - 1; i++) {
s1.push_back('R');
}
s1.push_back('D');
for (int i = 0; i < N - 1; i++) {
s1.push_back('L');
}
s1.push_back('D');
// 4. f(n,m,a,b)->f(n-2,m,a,b) DLLLLLLLLDRRRRRRRRRR
int secondrow = 0;
while (n - 1 > a) {
n -= 2;
secondrow++;
}
string s4;
s4.push_back('D');
for (int i = 0; i < N - 1; i++) {
s4.push_back('L');
}
s4.push_back('D');
for (int i = 0; i < N - 1; i++) {
s4.push_back('R');
}
// 2. f(n,m,a,b)->f(n,m-2,a,b-2) DRUR
int firstcol = 0;
while (b > 2) {
m -= 2;
b -= 2;
firstcol++;
}
string s2;
s2.push_back('D');
s2.push_back('R');
s2.push_back('U');
s2.push_back('R');
// 3.RURD
int secondcol = 0;
while (m - 1 > b) {
m -= 2;
secondcol++;
}
string s3;
s3.push_back('R');
s3.push_back('U');
s3.push_back('R');
s3.push_back('D');
for (int i = 0; i < firstrow; i++) {
cout << s1;
}
for (int i = 0; i < firstcol; i++) {
cout << s2;
}
if (a == 1 && b == 2) {
cout << "DR";
} else {
cout << "RD";
}
for (int i = 0; i < secondcol; i++) {
cout << s3;
}
for (int i = 0; i < secondrow; i++) {
cout << s4;
}
cout << endl;
}
int main() {
int T;
cin >> T;
while (T--) {
solve();
}
}

浙公网安备 33010602011771号