新的一年的第一个月都已经过了一个星期了,发现这个月至今还没有写一篇博客呢,于是就把之前学栈的时候写过的一个基于栈操作的迷宫问题求解给贴上来吧,哈哈哈。。。。
迷宫的描述:
用一个二维数组表示一个迷宫,这个二维数组的每一个元素的上下左右以及对角线上的四个方向,这总共加起来是八个方向,其中数字0表示可以通过,数字1表示此处不通,判断给定的一个迷宫是否有出路,有出路的话,求解出走出的路线。
存储结构的准备:
走迷宫的过程中每一个行走动作被记录下来保存在结构体中,其字段有当前位置的行号,列号,还有前进方向。前进方向又分为
row col direc
-1 0 0 上
-1 1 1 右上
0 1 2 右
1 1 3 右下
1 0 4 下
1 -1 5 左下
0 -1 6 左
-1 -1 7 左上
位置以及方向的结构体定义:
#pragma once
#include<fstream>
#include<string>
using namespace std;
class Offset
{
public:
int move_branch_row;//移动分支行
int move_branch_col;//移动分支列
int direction;//移动方向 用数字代替 便于计算
public:
Offset(){}
~Offset(){}
friend ofstream& operator<< (ofstream& output,Offset& O);
friend ifstream& operator>> (ifstream& input,Offset& O);
friend ostream& operator<< (ostream& output,Offset& O);
};
#include"offsets.h"
ofstream& operator<< (ofstream& output,Offset& O)
{
output<<"("<<O.move_branch_row<<","<<O.move_branch_col<<")"<<"Direction:"<<O.direction ;
return output;
}
ifstream& operator>> (ifstream& input,Offset& O)
{
input>>O.move_branch_row>>O.move_branch_col>>O.direction ;
return input;
}
ostream& operator<< (ostream& output,Offset& O)
{
output<<"("<<O.move_branch_row<<","<<O.move_branch_col<<")"<<"Direction:"<<O.direction ;
return output;
}
为了提高寻路的效率,还要考虑已走过的路不再重复走,这就需要借助一个大小一样的空矩阵(全为数字0),每走一个位置,就在这个空矩阵上的对应位置置为1,表示已走过。当有可能再次准备往这个位置走的时候判断,这个点是否已经被走过了,有的话直接跳到下一个方向上考虑。站在起始位置,理论上有8个方向可以走,但是也许是迷宫的边缘,也许是中间的不可通过,所以有若干位置可以走,一个小循环(移动分支的数目,8个循环次数)来试探每一步路,如果可以迈向下一步,那么就把当前位置记录下来,方向也一起存储在栈里,接下来重复,直到走到一个位置8次循环都没有下一步可走,那么就弹出栈顶元素,取出上一次的位置,取出上一次走过的方向,然后接着上一个位置的下一个方向试探。直到迷宫出口然后一次性输出这个栈中结构体信息,也就是行走的路线信息,这里使用的栈是自己编写的,所以加了一个一次性输出。还有就是大循环的条件是栈不为空,那么栈为空也会跳出,这时应该显示的是迷宫无解。
空矩阵:
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
迷宫矩阵:
1 1 1 1 1 1 1
0 0 1 0 1 0 1
1 1 0 0 0 1 1
1 1 1 1 0 0 1
1 1 0 1 0 0 1
1 1 0 0 1 0 1
1 1 1 1 1 1 0
迷宫的类定义:
#pragma once
#include"offsets.h"
const int row = 7; //迷宫数组信息的定义
const int col = 7;
const int exit_row = 6; //迷宫的出口
const int exit_col = 6;
const int begin_row = 1; //起始位置
const int begin_col = 0;
const int total_branchs = 8; //移动方向的分支数目
class Maze//迷宫
{
private:
Offset Move[total_branchs];//8个移动方向
int maze[row][col];//迷宫矩阵
int mark[row][col];//用作标记的矩阵
void SeekPath();//回溯寻求路径 参数为初始迷宫位置
public:
Maze();
~Maze();
void BackTracking();//回溯法出迷宫
//void print();//测试输出 数据
};
实现:
采用的全部是文件操作,包括两个二维矩阵的读入以及位置方向结构体信息的读入。
#include"Maze.h"
#include"S_stack.h"//自己的 栈头文件
#include<iostream>
using namespace std;
Maze::Maze()
{
ifstream in_mark("MARK.txt");
for(int r=0;r<row;r++)
{
for(int c=0;c<col;c++)
in_mark>>mark[r][c];//初始化 标志矩阵
}
in_mark.close();
ifstream in_maze("MAZE.txt");
for(int r=0;r<row;r++)
{
for(int c=0;c<col;c++)
in_maze>>maze[r][c];//初始化 迷宫矩阵
}
in_maze.close();
ifstream in_move("MOVE.txt");
for(int i=0;i<total_branchs;i++)
in_move>>Move[i];//初始化 8个移动分支
in_move.close();
}
Maze::~Maze()
{}
void Maze::SeekPath()//参数为迷宫入口坐标值 int current_row,int current_col
{
Offset move_elem;//定义一个 移动分支变量
Stack<Offset> stk_moveelem(row * col);//一个装载移动分支的栈 初始化矩阵个大小
int current_row,current_col,current_direction;//当前坐标值
int next_row,next_col,next_direction;//所选择的下一个移动方向的坐标值
move_elem.move_branch_row = begin_row;//初始化 记录迷宫入口
move_elem.move_branch_col = begin_col;
move_elem.direction = 0;//初始化从N方向开始顺时针循环8个移动分支
stk_moveelem.push(move_elem);//把迷宫入口地址记录在栈中
while(stk_moveelem.isEmpty() == false)
{
move_elem = stk_moveelem.pop();//把栈顶元素弹出
current_row = move_elem.move_branch_row;//取出上次走过的(在栈中存储的路径)信息
current_col = move_elem.move_branch_col;
current_direction = move_elem.direction;
while(current_direction < total_branchs)//8个移动分支内循环 未结束 继续进入循环
{
next_row = current_row + Move[current_direction].move_branch_row ;
next_col = current_col + Move[current_direction].move_branch_col ;//获取下一个移动分支的坐标值
if(current_row == exit_row && current_col == exit_col)//如果下一个分支的坐标值就是出口
{
cout<<"("<<exit_row<<","<<exit_col<<") exit"<<endl;
stk_moveelem.output();//一次性输出
//cout<<stk_moveelem;//输出栈中的记录坐标值 一路走过来的坐标信息 须重载栈输出
return ;
}
if(maze[next_row][next_col]==0 && mark[next_row][next_col]==0)//如果下一个分支为通路并且没走过
{
mark[next_row][next_col] = 1;//置为1 走过
move_elem.move_branch_row = current_row;
move_elem.move_branch_col = current_col;
move_elem.direction = current_direction;//这是一个将要被记录在栈中的坐标信息
stk_moveelem.push(move_elem);//压栈
current_row = next_row;//把所谓的下一个 置为当前坐标值 继续循环
current_col = next_col;
current_direction = 0;//进入下一个坐标后 方向要从0开始循环直至7位置
}
else
current_direction++;//试探下一个方向
}//内层while循环右括号
}//外层while循环右括号
//跳出外层while循环后
cout<<"no path maze"<<endl;//判断没有出口的迷宫
}
void Maze::BackTracking()
{
Maze::SeekPath();//核心算法封装
}
运行截图:
That's all;