C++迷宫寻路详解

迷宫寻路

题目
用一个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)
*/

总结
几个月前还做过类似的题目,当时花了好几个小时,今天又碰上这样的题目又去翻看原来的解法,我竟然又足足花了一下午才彻底明白过来,为什么呢?因为我当时只顾做,一点注释都没留下,所以注释真的很重要!

  • 2
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值