题目描述
给一 n×n 的字母方阵,内可能蕴含多个 yizhong
单词。单词在方阵中是沿着同一方向连续摆放的。摆放可沿着 88 个方向的任一方向,同一单词摆放时不再改变方向,单词与单词之间可以交叉,因此有可能共用字母。输出时,将不是单词的字母用 *
代替,以突出显示单词。
输入格式
第一行输入一个数 n。(7≤n≤100)。
第二行开始输入 n×n 的字母矩阵。
输出格式
突出显示单词的 n×n 矩阵。
本题自认为方法非常巧妙,有兴趣的大佬浅浅看一下,给点优化建议。
大致思路是dfs,(建议配合代码同时食用)如下:
需要解决的问题有三个:
- 如何保证后续搜索方向不改变
- 如何判断搜索到的字母是否符合条件
- 如何输出答案
由于本题需要沿着八个方向中的其中一个直线或斜线搜索,所以我为dfs添加了一个参数dir,保证在接下来搜索中按照既定方向,于是创建了go数组。
并且需要保证按照yizhong字母顺序对照,也就是第i个字母必须与字符串yizhong的第i个字母相等。故char一个t数组,第一个0只是起到占位作用。
由于只输出符合题意的字符串,其余的都输出*,所以创建一个bool类型的ans数组,一旦符合,将七个位置的bool值赋值为true,方便后续输出。
#include "iostream"
using namespace std;
int go[8][2] = {{-1,0},{-1,1},{0,1},{1,1},
{1,0},{1,-1},{0,-1},{-1,-1}};
int n;
char t[8]={'0','y','i','z','h','o','n','g'};
char g[105][105];
bool ans[105][105];
void dfs(int x,int y,int flag,int dir){//x,y代表当前搜索的位置坐标,flag代表搜索的字母序号,flag[3]就代表当前搜索的坐标的字母需要要等于z,dir则代表了搜索的方向
if(flag>7){//大于7说明所有的字母都搜索结束,可以用ans数组进行标记了
dir=(dir+4)%8;//将方向逆向,因为假设是字符串是从左向右的,那必须方向逆回去才能遍历到当初的那几个坐标
for(int i=1;i<=7;i++){
x+=go[dir][0],y+=go[dir][1];
ans[x][y]=true;//标记
}
}
if(g[x][y]!=t[flag])return;//如果当前的字母不符合,那么直接return掉就行
int nx=x+go[dir][0],ny=y+go[dir][1];//记录下一个搜索的坐标位置
if((nx<1||ny<1||nx>n||ny>n)&&g[x][y]!='g')return;//如果超限,return掉,标记该位置是不是g的原因是因为,如果不加这个条件,我都遍历结束了,但是g刚好在界内,但是下一个坐标会超界,那么就会被误return掉,不理解的话,可以把这个条件去掉试试,看看输出什么
dfs(nx,ny,flag+1,dir);//向下继续搜索
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cin>>g[i][j];//输入已知条件的循环
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(g[i][j]=='y'){//如果遍历到的字母是y,那么就可以后续的搜索,调用dfs函数
for(int k=0;k<8;k++)dfs(i+go[k][0],j+go[k][1],2,k);//y已经符合所以调用dfs函数首先要搜索的是字母i
}
for(int i=1;i<=n;i++){//输出结果的循环
for(int j=1;j<=n;j++){
if(ans[i][j])cout<<g[i][j];
else cout<<'*';
}
cout<<endl;
}
}
感谢观看!
--2024/03/03 23:27