迷宫问题深搜和广搜

迷宫求解是实验心理学中的一个经典问题,心理学家把一只老鼠从一个无顶盖的大盒子的入口处赶进迷宫,迷宫中设置很多隔壁,对前进方向形成了多处障碍,心理学家在迷宫的唯一出口处放置了一块奶酪,吸引老鼠在迷宫中寻找通路以到达出口。

输入: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;
} 

猜你喜欢

转载自blog.csdn.net/qq_39562286/article/details/80020514
今日推荐