迷宫寻路
题目
用一个5 × 5的二维数组,表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。
分析
1.使用一个比迷宫稍大的二维数组初始化为迷宫,简化位置判断。
2.通过使用栈stack保存每一步的位置,当走不通时回退。
3.每次访问迷宫中的一个位置,标记路径长度。
4.遍历和标记迷宫完成后,从终点位置回溯,把符合的点依次进栈,最后全部输出栈。
输入
一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。
输出
左上角到右下角的最短路径,格式如样例所示。
样例输入
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
样例输出
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
算法实现
// by wangzeng
#include<iostream>
#include<stack>
using namespace std;
const int M = 10;
const int N = 10;
int maze[M][N];
int visited[M][N];
//方向个数
const int DIRE = 4;
//用一个点记录位置
struct Point{
int x,y;
void init(int x,int y){
this->x = x;
this->y = y;
}
};
Point p1;
//起点
Point p2;
// 终点
Point MOVE[DIRE]={{-1,0},{0,-1},{0,1},{1,0}};
//四个方向的偏移量 :上、左、右、下
void init(){
for(int i=0;i<M;i++){
for(int j=0;j<N;j++){
maze[i][j] = 1;
visited[i][j] = 0;
}
}
int a,b;
// 题目给定迷宫大小为 5 * 5
a = 5;
b = 5;
// cin>>a>>b;
for(int i=1;i<=a;i++){
for(int j=1;j<=b;j++){
cin>>maze[i][j];
}
}
// 设置起点,左上角
p1.init(1,1);
// 设置终点,右下角
p2.init(a,b);
}
void findpath(){
stack<Point> p;
// 栈用于遍历迷宫
Point cur,nxt;
// 起点初始化栈
p.push(p1);
// 起点,初始化对应的值为 1
maze[p1.x][p1.y] = 1;
while(!p.empty()){
cur = p.top();
p.pop();
// 考察每一个相邻的其他位置
for(int i=0;i<DIRE;i++){
nxt.x = cur.x + MOVE[i].x;
nxt.y = cur.y + MOVE[i].y;
// 如果不是是墙壁
if(maze[nxt.x][nxt.y]==0){
// 不是墙壁,修改迷宫标记为走过的总长度
maze[nxt.x][nxt.y] = maze[cur.x][cur.y] + 1;
p.push(nxt);
// 已到终点
if(nxt.x == p2.x && nxt.y == p2.y){
break;
}
}
}
// 已到终点
if(nxt.x == p2.x && nxt.y == p2.y){
break;
}
}
// 如果栈大小等于0,表示起点无法到达终点
// 清空栈,用于后面重新保存路径
while(!p.empty()){
p.pop();
}
// 从终点回溯
cur = nxt;
// 路径长度
int len = maze[cur.x][cur.y] - maze[p1.x][p1.y];
// 起点未入栈,所以 len - 1
for(int i=len-1;i>=0;i--){
// 把符合的点依次入栈
p.push(cur);
for(int i=0;i<4;i++){
nxt.x = cur.x + MOVE[i].x;
nxt.y = cur.y + MOVE[i].y;
// 从终点回溯找到一个点,该点所在的长度小于当前长度,符合
if(maze[nxt.x][nxt.y]>1 && maze[nxt.x][nxt.y]<maze[cur.x][cur.y]){
break;
}
}
// 回溯到上一个点
cur = nxt;
}
// 加入起点
p.push(p1);
// p 记录了走过的路径
while(!p.empty()){
Point t = p.top();
cout<<"("<<t.x-1<<", "<<t.y-1<<")"<<endl;
p.pop();
}
// 查看迷宫状态
// for(int i=1;i<=p2.x;i++){
// for(int j=1;j<=p2.y;j++){
// cout<<maze[i][j]<<" ";
// }
// cout<<endl;
// }
}
int main(){
// 初始化样例
init();
findpath();
}
/*
输入样例:
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
*/
/*
输出结果:
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)
*/
总结
几个月前还做过类似的题目,当时花了好几个小时,今天又碰上这样的题目又去翻看原来的解法,我竟然又足足花了一下午才彻底明白过来,为什么呢?因为我当时只顾做,一点注释都没留下,所以注释真的很重要!