迷宫求解是实验心理学中的一个经典问题,心理学家把一只老鼠从一个无顶盖的大盒子的入口处赶进迷宫,迷宫中设置很多隔壁,对前进方向形成了多处障碍,心理学家在迷宫的唯一出口处放置了一块奶酪,吸引老鼠在迷宫中寻找通路以到达出口。
输入:1代表有障碍,0代表无障碍,2表示入口,3表示出口
问题一:求出一条通路,并打印路径
思想是://思路描述 借鉴了陈越老师主编的数据结构(第二版)第92页的写法,下面的广搜同样借鉴了这样的思路描述
(1)将初始入口坐标和起始方向信息放入堆栈中
(2)从堆栈中弹出位置信息,设置当前位置和当前尝试方向;
若堆栈为空而出口未找到,则迷宫没有解,程序退出
(3)在当前位置,从当前方向按顺序尝试剩余方向的可通性
如果某个方向可通,则把当前位置和下一个方向存入堆栈(因为当这个位置被弹出的时候,会从被存入的方向开始尝试)
如果可通位置是出口,则成功退出,堆栈中从栈低到栈顶的各个位置就是通路
如果可通位置不是出口,将该可通位置设为当前位置,并将第一个方向设为当前方向;再执行第三步
(4)当四个方向均不通时转第二步
/* 如果从入口到出口的话,需要从栈底到栈顶输出 所以在这里采用 从出口开始寻找入口 到最后是从栈顶到栈底输出 */ #include<iostream> #include<stack> using namespace std; /*--------坐标,以及要尝试的开始方向-------*/ struct Node{ int x,y,d; }; int N,dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}}; int maze[100][100],u[100][100]; /*--------把入口坐标和出口坐标传入-------*/ void dfs(int ix,int iy,int ox,int oy); int main() { int i,j,k,ix,iy,ox,oy; cin>>N; for(i=0;i<N;i++){ for(j=0;j<N;j++){ cin>>maze[i][j]; if(maze[i][j]==2){ ix= i;iy = j; } else if(maze[i][j]==3){ ox= i;oy = j; } } } dfs(ix,iy,ox,oy); return 0; } void dfs(int ix,int iy,int ox,int oy) { //stack<Node>s; Node tmp; stack<Node> s; int i,j,k,x,y,nx,ny,d; bool find = false; tmp.x = ox;tmp.y=oy;tmp.d = 0; u[ox][oy] = 1; s.push(tmp); /*--------当栈不为空,且没有找到出口时-------*/ while(!s.empty() && !find){ //s.empty()==0 x = s.top().x;y = s.top().y;d = s.top().d; s.pop(); //s.pop(); Node a = s.top(); while(d<4&&!find){ nx = x + dir[d][0]; ny = y + dir[d][1]; /*--------如果尝试的方向可行的话-------*/ if((nx>=0 && nx<N) && (ny>=0 && ny<N)&&!u[nx][ny]&& maze[nx][ny]!=1){ u[nx][ny] = 1; tmp.x = x; tmp.y = y; tmp.d= d+1; s.push(tmp); /*--------如果是出口的话,但是出口是作为尝试的方向,并没有进栈-------*/ if(nx==ix&&ny == iy){ find = true; break; } /*--------如果不是出口的话,就把尝试的位置设置为当前位置,并把要尝试的方向设置为0-------*/ x = nx;y = ny;d = 0; } /*--------如果此方向行不通的话,尝试下一个方向-------*/ else{ d++; } } } /*--------如果找到了,从栈顶到栈底依次输出-------*/ if(find){ printf("(%d,%d)\n",ix,iy); while(!s.empty()){ printf("(%d,%d)\n",s.top().x,s.top().y); s.pop(); } } else{ printf("NOT FOUND"); } }问题二:求出最短路径,打印路径,并显示走了几步
思路:
(1)将初始入口坐标放入队列中
(2)从队头中得到位置信息,设置当前位置;
若队列为空而出口未找到,则迷宫没有解,程序退出
(3)在当前位置,依次尝试相邻的四个方向
如果某个方向可通,则把可通位置入队,且记录可通位置的前一个点是当前位置
如果可通位置是出口,则成功退出,从出口坐标来依次寻找前一个点
循环二三步
/* 此时不难看出,当从出口寻找前一个点时,输出的是倒序,这里我们采用从出口找入口的方式 */ #include<iostream> #include<queue> using namespace std; struct Node { int x,y; Node(){ } Node(int i,int j){ x = i; y = j; } }mo[100][100]; int maze[100][100],u[100][100],N,dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}}; int bfs(int ix,int iy,int ox,int oy); int main() { int i,j,k,ix,iy,ox,oy; cin>>N; for(i=0;i<N;i++){ for(j=0;j<N;j++){ cin>>maze[i][j]; if(maze[i][j]==2){ ix= i;iy = j; } else if(maze[i][j]==3){ ox= i;oy = j; } } } cout<<bfs(ix,iy,ox,oy); return 0; } int bfs(int ix,int iy,int ox,int oy) { queue<Node>q; struct Node tmp; int i,j,k,x,y,nx,ny,cnt = 0; bool find = false; tmp.x = ox; tmp.y = oy; q.push(tmp); u[ox][oy] = 1; while(!q.empty() && !find){ tmp = q.front(); x = tmp.x; y = tmp.y; q.pop(); for(i=0;i<4;i++){ nx = x + dir[i][0]; ny = y + dir[i][1]; if((nx>=0 && nx<N)&& (ny>=0 && ny<N)&& !u[nx][ny] && maze[nx][ny]!=1){ u[nx][ny] =1; q.push(Node(nx,ny)); mo[nx][ny] = tmp; //printf("(%d,%d)<-(%d,%d)\n",tmp.x,tmp.y,nx,ny); if(nx == ix && ny == iy){ find = true; break; } } } } x = nx; y = ny; printf("(%d,%d)\n",ix,iy); while(!(x == ox && y == oy)){ cnt++; printf("(%d,%d)\n",mo[x][y].x,mo[x][y].y); int xx = mo[x][y].x; int yy = mo[x][y].y; x = xx; y = yy; } return cnt; }