Exp02 迷宫的求解
Author: Maskros
实验目的
输入迷宫,得到从入口到出口的(最短)路径
实验内容与要求
迷宫只有两个门,一个叫做入口,另一个叫做出口。把一只老鼠从一个无顶盖的大盒子的入口处赶进迷宫。迷宫中设置很多隔壁,对前进方向形成了多处障碍,在迷宫的唯一出口处放置了一块奶酪,吸引老鼠在迷宫中寻找通路以到达出口。求解迷宫问题,即找出从入口到出口的路径。
实验内容和实验步骤
分别通过深度优先搜索 (dfs) 和广度优先搜索 (bfs) 两种方法来实现实验要求
- 大体思路:
- dfs
O
(
m
∗
n
)
O(m*n)
O(m∗n)?:
- 结构体
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[][]
从终点逆推打印路径
- 结构体
- dfs
O
(
m
∗
n
)
O(m*n)
O(m∗n)?:
- 输入形式:首先输出两个正整数
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