数据结构实验二:迷宫的求解

Exp02 迷宫的求解

Author: Maskros

实验目的

输入迷宫,得到从入口到出口的(最短)路径

实验内容与要求

迷宫只有两个门,一个叫做入口,另一个叫做出口。把一只老鼠从一个无顶盖的大盒子的入口处赶进迷宫。迷宫中设置很多隔壁,对前进方向形成了多处障碍,在迷宫的唯一出口处放置了一块奶酪,吸引老鼠在迷宫中寻找通路以到达出口。求解迷宫问题,即找出从入口到出口的路径。

实验内容和实验步骤

分别通过深度优先搜索 (dfs) 和广度优先搜索 (bfs) 两种方法来实现实验要求

  • 大体思路:
    • dfs O ( m ∗ n ) O(m*n) O(mn)?:
      • 结构体point 存储点的信息,maze[][]存图,visit[][]判断是否访问过,dir[4][2]用于存储四个方向,便于查找
      • stack<point> s 栈用于存储最终路径
      • void dfs(int x,int y) 函数对坐标进行深度优先搜索,采用递归的思路,顺着一条路猛找,找不到返回上一级结点,直到找到为止。
      • void printpoint() 函数用于打印路径
      • void printmaze() 函数用于打印地图
    • bfs O ( m + n ) O(m+n) O(m+n)?:
      • 结构体node 存储点的信息,其中int l 表示从开始到该结点的距离,node father[][]数组用于存储当前节点的上一步是哪个结点,便于输出路径,其余变量同dfs
      • queue<node> q 用于读入可走的路径,在bfs中使用
      • bool check(int x,int y) 函数用于判断当前结点是否可走
      • int bfs(node s) 函数,结束标志为队空,从当前结点依次遍历可走的方向,如果可以继续走就将可走结点入队,如果走到终点即返回最短路径长度
      • string to_string(int s) 函数用于将int类型转为string类型,便于输出路径
      • void print()函数根据father[][]从终点逆推打印路径
  • 输入形式:首先输出两个正整数 m m m , n n n , 表示迷宫的有 n n n m m m 列,接下来输入迷宫序列, 1 表示可以通过, 0 表示不能通过。
  • 输出形式:以 bfs 实现的为例,首先输出最短路长度 l m i n l_{min} lmin , 接下来以 ( x i , x i ) (x_i,x_i) (xi,xi) -> $(x_j,y_j) $ … 表示这条路径,最后输出地图,用* 表示走过的路使结果更加直观;没有路径则输出-1

dfs实现(求一条路径)

//presented by Maskros - 2021/04/21
//dfs
#include<bits/stdc++.h>
using namespace std;
int m,n;
char maze[20][20];	//map
int vis[20][20]={0};	//check if visited
int dir[4][2]={		//four directrions
	{0,-1},{-1,0},{0,1},{1,0}
};
char ans[20][20];	
struct point{	
	int x,y;	//coordinate
	char d;		//Record direction
	point(){};
	point(int a,int b,char c):x(a),y(b),d(c){}
}pp;
char check(int x,int xx,int y,int yy){	//Check the direction of the path
	if(xx>x) return 'D';
	if(xx<x) return 'U';
	if(yy>y) return 'R';
	if(yy<y) return 'L';
	return '\0';
}
bool ed=false;
stack <point> s;
void dfs(int x,int y){	//Depth first search
	if(x>=m||x<0||y>=n||y<0) return ;	//Can't reach
	if(x==m-1&&y==n-1) {ed=true; return ;}	//reach destination
	int nx,ny;
	for(int i=0;i<4;i++){
		nx=x+dir[i][0];
		ny=y+dir[i][1];
		if((nx<m&&nx>=0&&ny<n&&ny>=0) && vis[nx][ny]==0 && maze[nx][ny]=='1'){
			vis[nx][ny]=1;
			dfs(nx,ny);
			if(ed==true){ s.push(point(nx,ny,check(x,nx,y,ny))); return ; }	//Recursive search the path
		}
	}
}
void printpoint(){	//Print path
	putchar('\n');
	char dd;
	bool st=false;
	while(!s.empty()){
		pp=s.top();
		s.pop();
		if(st) {dd=pp.d; cout<<dd<<")"<<endl;}
		else st=true;
		ans[pp.x][pp.y]='*';
		if(pp.x==m-1 && pp.y==n-1) dd='E';
		cout<<"("<<pp.y+1<<","<<pp.x+1<<",";
	}
	cout<<dd<<")"<<endl;
	return ;
}
void printmaze(){	//Print map
	cout<<endl;
	for(int i=0;i<m;i++){
		for(int j=0;j<n;j++){
			cout<<ans[i][j]<<" ";
		}
		cout<<endl;
	}
	return;
}
int main(){
	cin>>m>>n;
	for(int i=0;i<m;i++)
		for(int j=0;j<n;j++){
			cin>>maze[i][j];
			ans[i][j]=maze[i][j];
		}
	if(maze[0][0]=='0'||m==0||n==0||maze[m-1][n-1]=='0'){
		cout<<"no way";
		return 0;
	} 
	else {
		ans[0][0]='*';
		vis[0][0]=1;
	} 
	dfs(0,0);
	if(ed==false) {cout<<"no way"<<endl; return 0;}
	else s.push(point(0,0,'\0'));
	printpoint();
	printmaze();
	return 0;
}

bfs实现(求最短路)

//presented by Maskros - 2021/04/21
//bfs
#include<bits/stdc++.h>
using namespace std;
int m,n;
char maze[20][20];	//map
int vis[20][20]={0};	//check if visited
struct node{
	int x,y;	//coordinate
	int l;		//Path length
	node(){}
	node(int a, int b):x(a),y(b),l(0){}
	node(int a, int b, int ll):x(a),y(b),l(ll){}
};
node father[20][20];	//The previous node of the current node in the path
queue<node> q;	

int dir[4][2]={		//four directions
	{0,-1},{-1,0},{0,1},{1,0}
};
bool check(int x,int y){	//Judge if can go
	if(x>=0 && x<m && y>=0 && y<n && vis[x][y]==0 && maze[x][y]=='1')
		return true;
	else return false;
}

int bfs(node s){	//Breadth first search, based on queue
	int nx,ny;
	q.push(s);
	vis[s.x][s.y]=1;
	node tmp,next;
	while(!q.empty()){
		tmp=q.front();
		q.pop();
		if(tmp.x==m-1&&tmp.y==n-1)  return tmp.l;	//reach destination
		for(int i=0;i<4;i++){	//Look in four directions in turn
			nx=tmp.x+dir[i][0];
			ny=tmp.y+dir[i][1];
			if(check(nx,ny)) {
				next=node(nx,ny,tmp.l+1);
				father[nx][ny]=node(tmp.x,tmp.y);	//Record the previous node
				q.push(next);
				vis[nx][ny]=1;
			}
		}
	}
	return -1;
}
string to_string(int s){	//Convert int to string and save in the path
	string l;
	while(s){
		int tmp=s%10;
		l=char(tmp+'0')+l;
		s/=10;
	}
	return l;
}
void print(){ 		//Print path and map
	string s="("+to_string(m)+","+to_string(n)+")";
	node tt=father[m-1][n-1];
	maze[m-1][n-1]='*';
	while(1){
		s="("+to_string(tt.x+1)+","+to_string(tt.y+1)+") -> "+s;
		maze[tt.x][tt.y]='*';
		if(tt.x==0 && tt.y==0) break;
		tt=father[tt.x][tt.y];
	}
	cout<<s<<endl<<endl;
	for(int i=0;i<m;i++){
		for(int j=0;j<n;j++){
			cout<<maze[i][j]<<" ";
		}
		cout<<endl;
	}
	return ;
}
int main(){
	cin>>m>>n;
	for(int i=0;i<m;i++){
		for(int j=0;j<n;j++){
			cin>>maze[i][j];
		}
	}
	if(!check(0,0)){ cout<<-1; return 0;}	//Special case
	int lmin=bfs(node(0,0));	//Shortest path length
	if(lmin==-1) cout<<-1;
	else {
        cout<<endl;
		cout<<"The length of the way is: "<<lmin<<endl;
		print();
	}
	return 0;
}

实验用测试数据和相关结果分析

Test 1
5 5
1 1 1 1 1
0 0 0 0 1
1 1 1 1 1
1 0 0 0 0
1 1 1 1 1

Test 2
1 1
1

Test 3
1 5
1 1 0 1 1

Test 4
4 4
1 1 1 0
1 0 1 1
1 1 1 0
1 0 0 1

Test 5
9 7
1 1 1 1 1 1 1
0 0 0 0 0 0 1
1 1 1 1 1 1 1
1 0 1 0 0 0 0
1 1 1 1 1 1 1
0 0 0 0 1 0 1
1 0 1 1 1 1 1
1 0 1 0 1 0 1
1 0 1 1 1 0 1

  • 结果分析:无论是起点终点重合,没有通路,以及对最短路的寻找均有正确的输出

实验总结

  • 分别温习了栈和队列的使用,基于栈通过dfs递归爆搜出一条通路,以及基于队列通过bfs逐渐找到一条最短路径
  • 干,时间复杂度有点不会算
  • dfs 和 bfs 典中典,stl yyds
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值