如图,用1表示墙,用0表示通路,entry表示入口,exit表示出口,那么如何找到一条通路,用栈和递归方法都可以实现。
一.用栈求解
1.首先给定一个入口点,从入口点开始找。
2.将入口点压栈,以后遇到的每一个合法位置的数据也要压栈,并且标记出来,表示走过的路径。
3.判断哪些点能走通,也就是哪些点可以压栈,分别对当前位置的四个方向进行探测即可。找到能走的方向,循环上述过程。
4.如果四个方向都不通,就要回溯到前一个位置,再探测其他方向,直到有路可走。
5.如果回溯到入口点,则证明没有迷宫没有通路。
6.当走到所给定的出口点时,说明已经走出了迷宫。
#include <stack>
#include <iomanip>
template<size_t M, size_t N>
class Maze
{
public:
//用给定的数组初始化迷宫
Maze(int maze[M][N])
{
for (size_t i = 0; i < M; i++)
{
for (size_t j = 0; j < N; j++)
{
_maze[i][j] = maze[i][j];
}
}
}
//坐标
struct Pos
{
int _row;
int _col;
};
//检测坐标是否合法
bool CheckAccess(Pos next)
{
if (next._row >= 0 && next._row < M
&&next._col >= 0 && next._col < N
&&_maze[next._row][next._col] == 0) //坐标所表示的值也不能为“墙”
{
return true;
}
return false;
}
//找到一条通路
bool GetMazePath(Pos entry)
{
stack<Pos> path;
path.push(entry);
while (!path.empty())
{
//栈顶的坐标就是当前坐标
Pos cur = path.top();
//走过的路标记为2
_maze[cur._row][cur._col] = 2;
//已经找到出口
if (cur._row == M - 1)
return true;
//四个方向探测
//上
Pos next = cur;
next._row -= 1;
if (CheckAccess(next))
{
path.push(next);
continue;
}
//右
next = cur;
next._col += 1;
if (CheckAccess(next))
{
path.push(next);
continue;
}
//下
next = cur;
next._row += 1;
if (CheckAccess(next))
{
path.push(next);
continue;
}
//左
next = cur;
next._col -= 1;
if (CheckAccess(next))
{
path.push(next);
continue;
}
Pos back = path.top();
_maze[back._row][back._col] = 3;
path.pop();
}
return false;
}
void Print()
{
for (size_t i = 0; i < M; i++)
{
for (size_t j = 0; j < N; j++)
{
cout << setw(2);
cout << setiosflags(ios::right);
cout << _maze[i][j] << " ";
}
cout << endl;
}
cout << endl;
}
protected:
int _maze[M][N];
};
void TestMaze()
{
int maze[10][10] =
{
{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 1, 0, 1, 0, 0, 0, 0, 1, 1 },
{ 1, 1, 0, 1, 0, 1, 1, 0, 1, 1 },
{ 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 },
{ 1, 1, 1, 1, 1, 1, 1, 0, 1, 1 },
};
Maze<10, 10> m(maze);
Maze<10, 10>::Pos entry;
entry._row = 1;
entry._col = 0;
cout << m.GetMazePath(entry) << endl;
m.Print();
cout << endl;
}
二.递归求解
递归和用栈求解都需要不断探测四周的通路,但是递归是将下一次要走的位置当作入口点,不断探测递归。同样的,要是方向全不通,则要回溯,递归则是返回上一层。
bool GetMazePathR(Pos entry)
{
Pos cur = entry;
_maze[cur._row][cur._col] = 2;
// 已经找到出口
if (entry._row == N-1)
{
return true;
}
Pos next = cur;
// 上
next._row -= 1;
if (CheckAccess(next))
{
// 子问题
if (GetMazePathR(next))
return true;
}
// 右
next = cur;
next._col += 1;
if (CheckAccess(next))
{
if (GetMazePathR(next))
return true;
}
// 下
next = cur;
next._row += 1;
if (CheckAccess(next))
{
if (GetMazePathR(next))
return true;
}
// 左
next = cur;
next._col -= 1;
if (CheckAccess(next))
{
if (GetMazePathR(next))
return true;
}
//
_maze[cur._row][cur._col] = 3;
return false;
}
提示:在进行测试的时候,可以将表示迷宫的矩阵保存在文件中,需要的时候打开即可,最重要的是修改方便,所以建议使用这种方法。