寻找迷宫路径(C++描述)

一个迷宫可以用如下图描述

                                                

0表示可以通过,1表示有障碍物。问题是在图中是否可以找到一条路径,从入口(左上顶点)到出口(右下顶点)。

主要思想是回溯法和深度优先搜索

分析结合代码看会更好

首先走一步,然后判断是否到达出口,如果没有到达出口,则找到要移动的相邻的一步,(1)找到了,则保持好当前的位置(放入栈),然后移动到此找到的相邻的位置继续前进。那怎么继续前进?首先需要说明的是从一个点前进有四个选择,右,下,左,上这四个方向(可以分别用0,1,2,3表示)。那找到邻近点后要怎么前进?由于找到的是新的一个点,所以也就有四个方向可以走,有人会说肯定有一个方向行不通,因为当前位置就是从那个方向走来的,对,每当经过一个点,都会对此点进行标记(设置为障碍)以防重复访问,因此在遍历四个方向时如果遇到来的那个方向肯定没法过去,因为已经标记/设为障碍。(2)如果没有找到邻近的点呢,那么就退回到前一步,如果无路可退,则说明没法到达终点,返回结果。否则继续前进。那此时该怎么前进呢,肯定现在的这个方向不会再来了。那还需要像找到一个邻近点那样从四个方向开始遍历吗,不要那样做,有点太重复了,假如我们要退回到的点是next,当前点是here,肯定有这种关系next->here,退回去意思就是说退回到来的地方,也就是说当前位置here是从next来的,here是next的四个方向选择之一,在来here之前肯定也遍历了此位置之前的方向,我们知道遍历顺序是按照右,下,左,上来的,所以只要知道here是next的那个方向,接下要前进的那个方向不就确定了吗,这样就避免了重复。那具体该怎么确定呢,下面这段程序说明了此种情形

          if (next.first == here.first) {//next和here保持在了同一行,那么下一步要么上,要么下(完全看next和here的水平位置,如果是next->here,说明此时是右方向,那下一个方向就是下,option也就取1,如果是here<-next,说明此时是左方向,那下一个方向就是上,option也就取3,)
                option = 2 + next.second - here.second;
            }
            else {//同理可得,next和here保持在了同一列,那么下一步要么左,要么结束(上是最后一个方向,因此下一个方向就是结束,此时option是4)
                option = 3 + next.first - here.first;
            }

需要注意的点是为了在处理边界位置方便,能和内部位置处理方法保持一致,因此在地图外围新建了四堵墙。

程序代码如下:

#include<iostream>
#include<stack>
#include<vector>
#include<utility>
using namespace std;
bool findPath(vector<vector<int>>& mapIn)
{
	if (mapIn.empty()) {
		return false;
	}
	stack<pair<int, int>> path;
	//方向设定
	vector<pair<int, int>> offset = { { 0,1 },{ 1,0 },{ 0,-1 },{ -1,0 } };//分别代表右,下,左,上四个方向
    //初始化迷宫外面的障碍墙,这是为了处理边界位置时比较方便
	int n = mapIn.size();
	vector<int> vtemp(n + 2, 1);
	vector<vector<int>> map(n + 2, vtemp);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
		{//把之前的障碍搬到新的地图中
			map[i][j] = mapIn[i - 1][j - 1];
		}
	pair<int, int> here(1, 1);
	map[1][1] = 1;  //表示已经从出口出来了
	int option = 0, lastOption = 3;
	while (here.first < n || here.second < n)
	{//没有到达出口
	 //找到要移动的相邻的一步
		int r, c;
		while (option <= lastOption)
		{
			r = here.first + offset[option].first;
			c = here.second + offset[option].second;
			if (map[r][c] == 0) {//可以到达
				break;
			}
			++option;
		}
		if (option <= lastOption) {//相邻的一步找到了
			path.push(here);
			here.first = r;
			here.second = c;
			map[r][c] = 1;
			option = 0;
		}
		else {//没有邻近的一步可走,则退回到前一步,然后按照原理的节奏继续寻找,
			if (path.empty()) {//无路可退
				return false;
			}
			pair<int, int> next = path.top();
			path.pop();
			if (next.first == here.first) {//先前的节奏保持在了同一行,那么那一步要么上,要么下
				option = 2 + next.second - here.second;
			}
			else {//先前的节奏保持在了同一列,那么那一步要么左,要么结束
				option = 3 + next.first - here.first;
			}
			here = next;
		}
	}
	return true;
}
int main()
{
	vector<vector<int>> mapIn = { { 0,1,1,0,1,1 },
	                              { 0,0,1,0,1,0 },
	                              { 0,0,1,0,0,0 },
	                              { 1,0,0,0,1,0 },
	                              { 0,1,1,1,0,0 },
	                              { 0,1,1,1,0,0 } };
	cout << findPath(mapIn) << endl;
	system("pause");
	return 0;
}

 

当然如果要找的是最短路径,可以查看此文 https://blog.csdn.net/Jeff_Winger/article/details/81989982

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值