题解 P1101 【单词方阵】

Morning_Glory

2018-06-01 21:22:40

Solution

这道题可以用深搜(回溯)来写,相信大部分人都是这么想的,但是有些人可能在一些地方饶了半天,所以这里就贴一下我的思路,个人觉得自己的很好懂,除了tx和ty那里,但是tx和ty的那种用法对于输出路径的题目一般很实用 这个算是比较简单的吧,题目里给出了具体要找的字符串,我们要做的就是对它进行8个方向的搜索,所以先定一个方向,和要找的字符串 ```cpp const char key[8]={'y','i','z','h','o','n','g','\0'}; ``` ```cpp int dirx[8]={-1,-1,-1,0,0,1,1,1},diry[8]={-1,0,1,-1,1,-1,0,1}; ``` 配合着x,y分别是左上,正上,右上,正左,正右,左下,正下和右下 然而最后我们并不是只要是这些关键字就要保留的,所以我们只需记录下我们最后需要输出的坐标 ```cpp int used[105][105]; ``` 但是并不是每一个都需要去搜索的,只要在需要搜索的地方搜索就可以了 那么哪些需要搜索呢,最开始肯定是从字符'y'开始往里搜索啦,然后在开始搜索之前呢,先判断我们下一步往哪个方向进行搜索,这样就不需要每次都各个方向的去找了~~(废话)~~ 那么就先做个函数对找到的'y'进行确定下一步往哪个方向去找 ```cpp void start (int x,int y)//最开始找到的'y'的坐标 { int kx,ky,k;//临时坐标 for (k=0;k<8;k++){ kx=x+dirx[k];ky=y+diry[k];//各个方向都进行查找 if (kx<0||ky<0||kx>=n||ky>=n)//不能越界 continue; if (s[kx][ky]==key[1]){//如果找到了在方向上有'i'就往这个方向继续查找 locx=x;//先记录下我们的出发点 locy=y; dfs (kx,ky,1,k); } } } ``` 接下来是深搜的函数 ```cpp void dfs (int x,int y,int rank,int fx)//x,y是当前坐标,rank则是记录现在已经找到几个了,fx表示方向 { if (rank==6){used[locx][locy]=1;deal(x,y);return;}//这一步后面会解释,其实是全部找到了就对一路走过来的这几个打上'标记'意味着需要保留 int kx,ky; kx=x+dirx[fx];ky=y+diry[fx];//临时变量 if (kx<0||ky<0||kx>=n||ky>=n)//防止越界 return; if (s[kx][ky]==key[rank+1]){ tx[kx]=x;//记录下找到下一个字符的路径,表示kx是从x这来的 ty[ky]=y; dfs (kx,ky,rank+1,fx);//进行下一步搜索 tx[kx]=ty[ky]=-1;//把路径取消 } } ``` 之后就是我们的deal函数了,deal是对一直能够走到这条路的所有坐标进行处理让他们可以保留原样输出(used[x][y]=1) ```cpp void deal (int x,int y) { while (x!=-1&&y!=-1){//如果不是这条路的则是-1,前面定义了 used[x][y]=1;//将当前坐标打上标记 x=tx[x];//回到我们是怎么走过来的,即到上一步的地方去 y=ty[y]; } } ``` 最后顺便带了个输出函数 ```cpp void print (void) { for (int i=0;i<n;i++){ for (int j=0;j<n;j++) if (used[i][j])//如果是我们打过标记的,即是可以连成yizhong的坐标 cout<<s[i][j];//就原样输出 else cout<<'*';//否则就变成'*' cout<<endl;//记得换行,在下面的代码里为了防止作弊就将这条删掉了,注意注意 } } ``` 下面贴上代码 ```cpp #include <iostream> #include <cstring> using namespace std; const char key[8]={'y','i','z','h','o','n','g','\0'}; char s[105][105]; int n,dirx[8]={-1,-1,-1,0,0,1,1,1},diry[8]={-1,0,1,-1,1,-1,0,1},tx[105],ty[105],used[105][105],locx,locy; void deal (int x,int y) { while (x!=-1&&y!=-1){//如果不是这条路的则是-1,前面定义了 used[x][y]=1;//将当前坐标打上标记 x=tx[x];//回到我们是怎么走过来的,即到上一步的地方去 y=ty[y]; } } void dfs (int x,int y,int rank,int fx)//x,y是当前坐标,rank则是记录现在已经找到几个了,fx表示方向 { if (rank==6){used[locx][locy]=1;deal(x,y);return;}//这一步后面会解释,其实是全部找到了就对一路走过来的这几个打上'标记'意味着需要保留 int kx,ky; kx=x+dirx[fx];ky=y+diry[fx];//临时变量 if (kx<0||ky<0||kx>=n||ky>=n)//防止越界 return; if (s[kx][ky]==key[rank+1]){ tx[kx]=x;//记录下找到下一个字符的路径,表示kx是从x这来的 ty[ky]=y; dfs (kx,ky,rank+1,fx);//进行下一步搜索 tx[kx]=ty[ky]=-1;//把路径取消 } } void start (int x,int y)//最开始找到的'y'的坐标 { int kx,ky,k;//临时坐标 for (k=0;k<8;k++){ kx=x+dirx[k];ky=y+diry[k];//各个方向都进行查找 if (kx<0||ky<0||kx>=n||ky>=n)//不能越界 continue; if (s[kx][ky]==key[1]){//如果找到了在方向上有'i'就往这个方向继续查找 locx=x;//先记录下我们的出发点 locy=y; dfs (kx,ky,1,k); } } } void print (void) { for (int i=0;i<n;i++){ for (int j=0;j<n;j++) if (used[i][j]) cout<<s[i][j]; else cout<<'*';//这里注意,注意 } } int main () { cin>>n;//输入n memset(tx,-1,sizeof(tx));//将每个路径都记为-1 memset(ty,-1,sizeof(ty)); for (int i=0;i<n;i++) for (int j=0;j<n;j++) cin>>s[i][j]; for (int i=0;i<n;i++) for (int j=0;j<n;j++) if (s[i][j]==key[0])//如果找到了符合条件的开头字符'y' start (i,j);//先进行处理 print();//输出 return 0; } ```