老鼠走迷宫
问题描述
老鼠走迷宫是递回求解的基本题型,试以程式求出由入口至出口的路径,入口为左上角,出口为右下角。
迷宫图7×7
墙的表示:█ 路径的表示:◇
INPUT
(无)
OUTPUT
显示迷宫:
显示路径:
解法一
[解题思路]
深度搜索,在题的基础上考虑了多种路径到达终点的状况,输出最短路径,需要注意的是a[index].ans[new_x][new_y]=0;
[代码实现]
#include<iostream>
using namespace std;
const int N=7;
/* 地图,1表示障碍 0表示可用 */
int Map[N][N]={ 1,1,1,1,1,1,1,
1,0,0,0,0,1,1,
1,0,1,1,1,0,1,
1,0,1,0,0,0,1,
1,0,1,0,1,0,1,
1,0,0,0,1,0,1,
1,1,1,1,1,1,1 };
int book[N][N]; /* 标记 */
/* 为了找出最短路径 */
struct node
{
int step; /* 所用步数 */
int ans[N][N]; /* 一种路径 */
}a[100];
int index=0,min_index; /* 最少步数的下标 */
int Min=9999; /* 最小步数 */
const int end_x=5,end_y=5; /* 终点 */
/* 方向 */
int Next[4][2] = {{0, 1},{1, 0},{0, -1},{-1, 0}};/*右,下,左,上*/
void dfs(int x,int y,int Step)
{
a[index].ans[1][1]=2; /* 起点标记 */
if(x==end_x && y==end_y)
{
a[index].step=Step; /* 保存步数 */
if(Step<Min)
{
Min=Step; /* 更新 min step */
min_index=index; /* 只要输出最小步数的路径,所以记录下来 */
}
index++;
return ;
}
for(int i=0;i<=3;i++)
{
int new_x=x+Next[i][0];
int new_y=y+Next[i][1];
if(new_x<1 || new_x>N-1 ||new_y<1 ||new_y>N-1) /* 越界 */
{
continue;
}
if(book[new_x][new_y]==0 && Map[new_x][new_y]!=1) /* 没有使用过,并且没有障碍*/
{
book[new_x][new_y]=1;
a[index].ans[new_x][new_y]=2;
dfs(new_x,new_y,Step+1);
a[index].ans[new_x][new_y]=0;
book[new_x][new_y]=0;
}
}
}
void print()
{
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
{
if(Map[i][j]==0)
{
if(a[min_index].ans[i][j]==2)cout<<"◇";
else cout<<" ";
}
else cout<<"█";
if(j==N-1) cout<<endl; /* 格式控制 */
}
cout<<endl;
}
int main()
{
print();
dfs(1,1,0);
print();
return 0;
}
解法二
[解题思路]
广度优先搜索,找最短路径。利用队列实现。
[代码实现]
#include<iostream>
using namespace std;
struct note
{
int x; //横坐标
int y; //纵坐标
int f; //父亲在队列中的编号
int s; //步数
}que[100];
const int N=8;
int Book[N][N]={0}; //标记是否已经扩展
//迷宫初始化
int Map[N][N]={ 0,0,0,0,0,0,0,0,
0,1,1,1,1,1,1,1,
0,1,0,0,0,0,1,1,
0,1,0,1,1,1,0,1,
0,1,0,1,0,0,0,1,
0,1,0,1,0,1,0,1,
0,1,0,0,0,1,0,1,
0,1,1,1,1,1,1,1 };
//定义一个用于表示走的方向的数组
int Next[4][2] = { {0, 1}, //右
{1, 0}, //下
{0, -1}, //左
{-1, 0} }; //上
int head=1;int tail=1; //队列初始化
void pfs(int start_x,int start_y,int end_x,int end_y);
void print(int start_x,int start_y);
int main()
{
int start_x,start_y; //开始位置
int end_x,end_y; //目标位置
start_x=2;start_y=2; //起点初始化
end_x=6;end_y=6; //终点初始化
pfs(start_x,start_y,end_x,end_y); //广度
print(start_x,start_y); //显示
return 0;
}
void pfs(int start_x,int start_y,int end_x,int end_y)
{
int new_x,new_y; //扩展的x,y
//往队列插入迷宫入口坐标
que[tail].x=start_x;
que[tail].y=start_y;
que[tail].f=0;
que[tail].s=0;
tail++;
Book[start_x][start_y]=1;
int flag=0; //用来标记是否到达目标点,0表示暂时还没有到达,1表示到达
//队列不为空循环
while(head<tail)
{
//枚举4个方向
for(int i=0;i<4;i++)
{
//计算下一个点的坐标
new_x=que[head].x+Next[i][0];
new_y=que[head].y+Next[i][1];
//判断是否越界
if(new_x<1 || new_x>N-1 || new_y<1 || new_y>N-1)
{
continue;
}
//判断是否是障碍物或者已经在路径中
if(Book[new_x][new_y]==0 && Map[new_x][new_y]==0)
{
//把这个点标记为已经走过
//注意宽搜每个点只入队一次,所以和深搜不同,不需要将Book还原
Book[new_x][new_y]=1;
que[tail].x=new_x;
que[tail].y=new_y;
que[tail].f=head; //因为这个点是从head扩展出来的,所以它的父亲是head
que[tail].s=que[head].s+1; //步数是父亲的步数+1
tail++;
}
if(new_x==end_x && new_y==end_y)
{
flag=1;
break;
}
}//for循环结束
if(flag==1)
{
break;
}
head++;
}//while循环结束
}
void print(int start_x,int start_y)
{
//打印队列中末尾最后一个点(目标点)的步数
//注意tail是指向队尾(即最后一位)的下一个位置,所以这需要-1
//printf("%d",que[tail-1].s);
int temp=tail-1;
//将路径标为2用于输出
while(1)
{
Map[que[temp].x][que[temp].y]=2;
temp=que[temp].f;
if(que[temp].x==start_x && que[temp].y==start_y) //当父亲结点是起点时候结束
{
Map[que[temp].x][que[temp].y]=2;
break;
}
}
//打印迷宫
for(int i=1;i<N;i++)
{
for(int j=1;j<N;j++)
{
if(Map[i][j]==1)
{
cout<<"█";
}
if(Map[i][j]!=1)
{
cout<<" ";
}
}
cout<<endl;
}
//打印路径
for(int i=1;i<N;i++)
{
for(int j=1;j<N;j++)
{
if(Map[i][j]==1)
{
cout<<"█";
}
if(Map[i][j]==2)
{
cout<<"◇";
}
if(Map[i][j]==0)
{
cout<<" ";
}
}
cout<<endl;
}
}