这道题用到了递归思想,递归这种东西挺抽象的,还是那句话,切忌头脑编译,选个简单例子在纸上画一下,整道题的逻辑就会清晰很多。这道题老师上课有讲,也在电脑上打过代码,当时听的一知半解,又不爱动手算,这道题搁置了差不多两个星期我才着手写。
下面是我的解析。
1、首先,定义两个全局数组变量a[4]={1,-1,0,0}和b[4]={0,0,1,-1},这两个数组是用来控制方向的。
for(int i=0;i<3;i++)
{
int nx=x+a[i];
int ny=y+b[i];
if(c[nx][ny]!='1')//没走过或者不是墙
{
c[nx][ny]='1';//走过的地方标记为1,避免死循环
dfs(nx,ny);
}
}
当i=0时,a[0]=1,b[0]=0,那么nx=x+a[i],ny=y+b[i],相当于往下走了一步;当i=1时,a[1]=-1,b[1]=0,相当于往上走了一步;当i=2时,a[2]=0,b[2]=1,相当于往右走了一步;当i=3时,a[3]=0,b[3]=-1,相当于往左走了一步
2、在上面的代码段中,有 if(c[nx][ny]!='1')//没走过或者不是墙
{
c[nx][ny]='1'; //走过的地方标记为1,避免死循环
dfs(nx,ny); //以新走到的格子为中心调用函数
}
当c[nx][ny]!='1'时,即c[nx][ny]==0,说明这个格子可以走,并且没有走过,那么就往这个格子走一步,同时赋值1,再调用函数dfs(nx,ny),即以这个格子为中心,往它的上下左右试探方向。当它的上方或下方或左方或右方格子的值为1时,就一直进行for循环,直到找到一个不为1的格子为之,这样才能继续往下走。那如果这个格子的上下左右都为1,那说明走到了一条“死路”,此时递归就会回到上一个格子,以上一个格子为中心,再次搜索上下左右。
下面以3*3的迷宫为例进行解释。
3 3
0 1 0
0 1 1
0 0 0
1、先以c[1][1]为中心搜索,for循环第一次有nx=2,ny=1,即往下走,发现c[2][1]==0,没有走过,那我就把c[2][1]标记为1,接着调用函数,以c[2][1]为中心进行搜索
2、此时c[2][1]为中心,第一次循环有nx=3,ny=1,即往下走,发现c[3][1]==0,也没有走过,把c[3][1]标记为1,调用函数,以c[3][1]为中心进行搜索
3、此时c[3][1]为中心,第一次循环有nx=4,ny=1,即往下走,发现走到了墙走不了了,第二次循环有nx=2,ny=1,即往上走,也走过了,进行第三次循环,有nx=3,ny=2,即往右走,c[3][2]==0,没有走过,那就往c[3][2]走,并把它标记为1,再调用函数,以c[3][2]为中心进行搜索
4、此时c[3][2]为中心,同理,循环到第三次,往右走,走到c[3][3],此时dfs(3,3),满足了递归结束条件(x==n && y==m)即走到了迷宫出口
下面是全部代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int n,m,ok=0;
char c[105][105]={' '};
int a[4]={1,-1,0,0};
int b[4]={0,0,1,-1};//每次递归判断四个方向(上下左右)是否可以走
//下上右左
void dfs(int x,int y)//dfs——深度优先算法
{
if(x==n && y==m)//出口坐标为(n,m) //递归结束条件放在前面
{
ok=1;//走到出口
return ;
}
for(int i=0;i<3;i++)
{
int nx=x+a[i];//试探方向
int ny=y+b[i];
if(c[nx][ny]!='1')//该点没走过或者该点不是墙
{
c[nx][ny]='1';//走过的地方标记为1,避免死循环
dfs(nx,ny);//以这个刚走到的点为中心递归进行搜索
}
}
}
int main()
{
int i,j;
cin >> n >> m;//n行m列
for(i=0;i<105;i++)
{
for(j=0;j<105;j++)
{
c[i][j]='1';//全部标为'1','1'表示不可走
}
}
for(i=1;i<=n;i++)//n行m列外的周围相当于围墙
{
for(j=1;j<=m;j++)
{
cin >> c[i][j];//输入圈内的数据
}
}
dfs(1,1);//从入口开始调用函数
if(ok==1)
cout<< "yes";
else
cout<< "no";
return 0;
}