📚 算法笔记:P1101 单词方阵 (模拟与搜索)
1. 题目简述
在一个 N × N N \times N N×N 的字母方阵中找出所有的 yizhong。单词可以沿 8 个方向(上、下、左、右、左上、右上、左下、右下)直线延伸。不属于任何一个 yizhong 单词的字符需用 * 代替。
2. 核心代码 (C++ 实现)
C++
#include<bits/stdc++.h>
using namespace std;
// 全局变量:存起点坐标、地图、标记位
int Record[10005][2], cnt = 0;
char Init[105][105];
bool mark[105][105];
// 核心工具:8方向偏移量数组
int dx[] = {-1, -1, -1, 0, 0, 1, 1, 1};
int dy[] = {-1, 0, 1, -1, 1, -1, 0, 1};
string target = "yizhong";
int n;
void Find()
{
for(int k = 1; k <= cnt; k++)
{ // 遍历所有记录好的 'y'
int r = Record[k][0];
int c = Record[k][1];
for (int i = 0; i < 8; i++)
{ // 尝试8个方向
bool flag = true;
// 顺着当前方向检查接下来的6个字母(i,z,h,o,n,g)
for (int step = 1; step <= 6; step++)
{
int nr = r + dx[i] * step;
int nc = c + dy[i] * step;
// 边界判定 + 字符匹配判定
if (nr < 1 || nr > n || nc < 1 || nc > n || Init[nr][nc] != target[step])
{
flag = false;
break;
}
}
// 如果整条线匹配成功,则标记(染色)
if(flag)
{
for(int step = 0; step <= 6; step++)
{
mark[r + dx[i] * step][c + dy[i] * step] = true;
}
}
}
}
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
cin >> Init[i][j];
if(Init[i][j] == 'y')
{ // 记录所有可能的起点
cnt++;
Record[cnt][0] = i;
Record[cnt][1] = j;
}
}
}
Find();
// 输出逻辑:根据标记位决定输出字符还是 '*'
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (mark[i][j]) cout << Init[i][j];
else cout << "*";
}
cout << "\n";
}
return 0;
}
3. 核心考点与注意事项
🔍 核心考点
- 方向数组 (Direction Array) :利用
dx[],dy[]将 8 个方向的逻辑抽象化,避免冗长的if-else判断。 - 向量伸缩搜索 :通过
(r + dx[i]*step, c + dy[i]*step)实现直线搜索,确保搜索不拐弯。 - 辅助标记数组 (Mark Array) :使用
bool mark[][]记录结果。这是处理"先搜索、后处理"类题目的标准做法。 - 空间换时间 :预先存储
'y'的坐标,避免对整个地图进行盲目搜索。
⚠️ 注意事项
- 边界检查 :在访问数组下标前,必须判断
nr和nc是否在1 ~ n之间,防止内存越界。 - 数据类型 :存储地图要用
char,比较字符要用单引号'y'。 - 输入优化 :蓝桥杯数据量大时,记得加
ios::sync_with_stdio(0)。
4. 易错点回顾 (My Mistakes)
- 方向数组索引对齐 :数组
dx[8]的索引是0~7,循环写成1~8会导致漏搜方向且越界。 - 直线逻辑缺失 :初期容易漏掉
step偏移乘法,导致无法保持直线。 - 输入漏项 :在循环中误加
break导致只读取了部分地图。