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

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
    评论
/* ****迷宫算法求解************* */ /**计目标:教学演示**************/ #include<stdio.h> #define rows 10 #define cols 10 typedef struct {int row; int col; }PosType;/* //坐标点结构 */ typedef struct {int ord;/*//通道块在路径上的“序号” */ PosType seat;/*//通道块在迷宫中的“坐标位置”*/ int di;/*//从此通道快走向下一通道块的“方向” */ }SElemType;/*//的元素类型 */ typedef struct {SElemType *base; SElemType *top; int stacksize; }SqStack;/*//堆结构 */ void InitStack(SqStack &s)/*//初始化堆 */ { s.base=(SElemType *)malloc(100*sizeof(SElemType)); if(!s.base) return NULL; s.top=s.base; s.stacksize=100; } int StackEmpty(SqStack s)/* //空判别*/ {return(s.top==s.base); } void Pop(SqStack &s ,SelemType &e)/*//弹 */ {e=*--s.top); } void Push(SqStack &s,SElemType e)/*//将元素压入堆*/ { *s.top++=e; } /*static int maze[rows][cols]= {{0,0,0,0,0,0,0,0,0,0}, {0,1,1,0,1,1,1,0,1,0}, {0,1,1,0,1,0,1,0,1,0}, {0,1,1,0,1,0,0,1,1,0}, {0,1,1,0,0,1,1,1,1,0}, {0,1,1,1,0,1,1,1,1,0}, {0,1,0,1,1,1,0,1,1,0}, {0,1,0,0,0,1,0,0,1,0}, {0,0,1,1,1,1,1,1,1,0}, {0,0,0,0,0,0,0,0,0,0}, }; */ /* //初始迷宫数据(1-通,0-不通)*/ static int maze[rows][cols]= {{0,0,0,0,0,0,0,0,0,0}, {0,1,1,0,1,1,1,0,1,0}, {0,1,1,0,1,0,1,1,1,0}, {0,1,1,1,0,0,0,0,1,0}, {0,1,0,0,0,1,1,1,1,0}, {0,1,0,1,0,1,0,0,0,0}, {0,1,0,1,1,1,0,1,1,0}, {0,1,0,1,0,0,0,0,1,0}, {0,0,1,1,1,1,1,1,1,0}, {0,0,0,0,0,0,0,0,0,0}, }; /* //初始迷宫数据(1-通,0-不通)*/ static int foot[10][10]={0};/*//标记某点是否走过(1-走过,0-未走过)*/ void printpath(SqStack &s)/*//打印迷宫通路*/ {int i,j; SElemType e; while(!StackEmpty(s)) { Pop(s,e); foot[e.seat.row][e.seat.col]=1; } for(i=0;i<10;i++) {printf("\n"); for(j=0;j<10;j++) if(foot[i][j]) printf(" # "); else printf(" . "); } } int Pass(PosType pos)/*//判断当前的通道块是否可通*/ { return(maze[pos.row][pos.col]); }; void FootPrint(PosType pos) { maze[pos.row][pos.col]=0; } PosType NextPos(PosType curpos,int dir)/*//取当前通道块的下一个通道块*/ { switch(dir) {case 1: curpos.row++; break; case 2: curpos.col++; break; case 3: curpos.row--; break; case 4: curpos.col--; } return curpos;/*//将下一个通道块变为当前通道块*/ } int END(PosType curpos,PosType end) {return(curpos.row==end.row && curpos.col==end.col); } void MazePath(SqStack &s,PosType start,PosType end) {PosType curpos,nextpos; int curstep; SElemType e; SqStack *s; s=InitStack(); curpos=start; curstep=1; do{ if(Pass(curpos)) {FootPrint(curpos); e.ord=curstep;e.seat=curpos;e.di=1; Push(s,e); if(END(curpos,end)) return s; curpos=NextPos(curpos,1); curstep++; }/* end of if */ else { if(!StackEmpty(s)) { e=Pop(s); while(e.di==4 && !StackEmpty(s)) {FootPrint(e.seat);/* The same fuction as MarkPrint ? */ e=Pop(s); }/* end of while */ if(e.di<4) {e.di++;Push(s,e); curpos=NextPos(e.seat,e.di); } /* end of if */ } /* end of if */ } /* end of else */ }while(!StackEmpty(s)); curstep=0; return NULL; } void main() {SqStack *s; static PosType start={1,1},end={8,8}; s=MazePath(start,end); if(s) printpath(s); else printf("\n NO find the path!"); }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值