一个迷宫可以用如下图描述
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