题目描述:
有一个 m×n 格的迷宫(表示有 m 行、n 列),其中有可走的也有不可走的,如果用 0 表示可以走,1表示不可以走,起始点(1,1)、结束点(8,8)(起始点和结束点都是用两个数据来描述的,分别表示这个点的行号和列号)。现在要你编程找出所有可行的道路,要求所走的路中没有重复的点,走时只能是上下左右四个方向。如果一条路都不可行,则输出相应信息
算法思路:
迷宫问题需要考虑的一个点是当此路不通时需要进行回退,且回退次数不确定,这种回退的思想与栈的“后进先出”很契合,所以选择用栈来实现该算法,将每走一步的位置存储在栈中,当进行回退时只要出栈即可。具体实现方式如下。
一、迷宫构造
用二维数组存储迷宫,0代表可行道路,1代表墙壁。首先设置地图初始化函数和显示函数
//迷宫设置
void mazeset(int (&maze)[LENGTH][WIDTH])
{
//边框设值
for (int i = 0; i < WIDTH; i++)
{
if (i == 0 || i == LENGTH - 1)
{
for (int j = 0; j < LENGTH; j++)
{
maze[i][j] = 1;
}
}
else
{
for (int j = 1; j < LENGTH - 1; j++)
{
maze[i][j] = 0;
}
maze[i][0] = 1;
maze[i][WIDTH - 1] = 1;
}
}
//地图设值 此处可以改为手动输入设置墙壁障碍
maze[1][3] = 1;
maze[2][3] = 1;
maze[1][7] = 1;
maze[2][7] = 1;
maze[3][5] = 1;
maze[3][6] = 1;
maze[4][2] = 1;
maze[4][3] = 1;
maze[4][4] = 1;
maze[5][4] = 1;
maze[6][2] = 1;
maze[6][6] = 1;
maze[7][2] = 1;
maze[7][3] = 1;
maze[7][4] = 1;
maze[7][6] = 1;
maze[7][7] = 1;
maze[8][1] = 1;
//cout << maze[0][0] << endl;
}
//迷宫显示
void mazeshow(int(&maze)[LENGTH][WIDTH])
{
for (int i = 0; i < WIDTH; i++)
{
for (int j = 0; j < LENGTH; j++)
{
cout << maze[i][j]<<"\t ";
}
cout <<endl<< endl;
}
}
显示效果:
二、方向试探
//方向试探
typedef struct
{
// [-1][0]上
//[0][-1]左 [0][1]右
// [ 1][0]下
int incX, incY;
}Direction;
构造一个结构体Direction用来表示方向,(-1,0)(1,0)(0,-1)(0,1)分别表示上下左右,由于目标位置处于初始位置的右下方,所以按照“右下左上”的顺序对其进行初始化。
//Direction direct[4] = {(0,1),(1,0),(0,-1),(-1,0)};//这种赋值方法会出bug,没搞明白
Direction direct[4];
direct[0].incX = 0;
direct[0].incY = 1;
direct[1].incX = 1;
direct[1].incY = 0;
direct[2].incX = 0;
direct[2].incY = -1;
direct[3].incX = -1;
direct[3].incY = 0;
即在右边位置可行时尝试下方、下方不可行时尝试左方、左方不可行时尝试上方。当四个方向都不可行时进行退步。
三、移动位置存储
采用栈来对位置进行存储,首先构造一个结构体Box来表示位置。di用做direct的索引,0,1,2,3分别代表右下左上。
//栈中元素
typedef struct
{
//栈中元素为三元组,x,y坐标和方向
int x,y;
int di;
}Box;
其次是栈的构造,可以直接使用<stack.h>中的栈,但本文属于栈的学习和应用,所以手动构建了一个模板栈。
//栈
template <class DataType>
class Stack
{
private:
DataType* data;
int size;
int top;
public:
Stack();
Stack(int s);
~Stack();
void push(DataType ch);//入栈
DataType pop();//出栈
DataType getTop();//获取栈顶元素
bool isEmpty();//判断栈是否为空
bool isFull();//是否栈满
void setNULL();//将栈置为空
class Full {};//异常内部类,直接抛出即可
class Empty {};
};
模板栈的优势在于可以适应任意数据类型,不受栈中元素类型限制,在使用时确定其数据类型即可。
所有准备工作做好以后即可开始实现路径寻找算法(算法步骤注释很详细,如果还是看不懂可参考B站懒猫老师视频讲解,本文即视频算法思路的实现):
bool findPath(int maze[LENGTH][WIDTH],Direction direct[],Stack<Box> &s)
{
//寻找路径的顺序:右下左上
Box temp;
int x, y, di;//迷宫格子当前处理单元的纵横坐标和方向
int line, col;//迷宫下一单元的横纵坐标
maze[1][1] = -1;//起始点,-1表示来过
temp.x = 1;
temp.y = 1;
temp.di = -1;
//temp = { 1,1,-1 };
s.push(temp);//初始点压入栈中,此处di赋值为-1是为了进入第一个while循环后进行方向试探
while (!s.isEmpty())
{
temp = s.pop();//栈顶元素出栈后对该元素进行操作
//首个元素会进行出栈操作,其后的元素仅在第二个while循环条件不满足,即四个方向都不可达时才会进行出栈操作(出栈操作相当于向后退一步,若退后一步可以找到一个新方向则向新方向前进,若找不到则再次回退),若某个方向可达时只会进行入栈,而不会出栈。
x = temp.x;
y = temp.y;
di = temp.di+1;
while (di < 4)//四个方向进行尝试,当四个方向都尝试完其都不可达时,
//再次进入第一个while循环,从栈中取出新的栈顶元素
{
//下一步的横纵坐标
line = x + direct[di].incX;
col = y + direct[di].incY;
//下一步若可到达
if (maze[line][col] == 0)
{
temp = { x,y,di };
//记录当前所走的位置,即压入栈中
s.push(temp);
x = line;
y = col;
maze[line][col] = -1;
//注释掉部分用于画出路径箭头,效果不太好
//if (di == 0)
//{
// maze[line][col] = -1;
//}
//else if (di == 1)
//{
// maze[line][col] = -2;
//}
//else if (di == 2)
//{
// maze[line][col] = -3;
//}
//else if (di == 3)
//{
// maze[line][col] = -4;
//}
if (x == M && y == N)
{
cout << endl;
for (int i = 0; i < WIDTH; i++)
{
for (int j = 0; j < LENGTH; j++)
{
cout << maze[i][j] << "\t";
//也是画箭头
//if (maze[i][j] == 0 || maze[i][j] == 1)
//{
// cout << maze[i][j]<<"\t";
//}
//else if (maze[i][j] == -1)
//{
// cout << "->" << "\t";
//}
//else if (maze[i][j] == -2)
//{
// cout << "||" << "\t";
//}
//else if (maze[i][j] == -3)
//{
// cout << "<-" << "\t";
//}
//else if (maze[i][j] == -4)
//{
// cout << "^|" << "\t";
//}
}
cout << endl << endl;
}
return true;
}
else
di = 0;
}
//下一步若不可到达则按顺序进行下一个方向的尝试
else
di++;
}
}
cout << endl;
//mazeshow(maze);//mazeshow函数会参数报错,没搞明白
//这块是为了在找不到路是看一下是怎么走的,
for (int i = 0; i < WIDTH; i++)
{
for (int j = 0; j < LENGTH; j++)
{
cout << maze[i][j] << "\t ";
}
cout << endl << endl;
}
return false;
}
最终实现效果(最后一行1即代表找到可到达路径):