回溯——迷宫问题

问题描述:用一个N 阶矩阵来表示一个迷宫,该矩阵包含元素 0 1 -2 -3分别表示通道、墙、入口、出口。从入口处开始沿着通道行经,判断是否能够到达出口。

思路分析:问题的关键包括以下几个部分

  • 建立迷宫包括墙、通道、入口、出口
  • 点的移动
  • 走过的路径如何处理
  • 当前路径不可行后如何回溯
  • 终止条件

如何建立迷宫

用二维数组建立一个N阶矩阵,数组中的成员为结构体Point(表示点),每个点包含坐标(X,Y),状态Stu(表示通道、入口、墙、出口、以及BACKTRACKED标示该点是否通行过)

点的状态信息(用于建立迷宫)
enum STATU
{
	END = -3,//出口
	BEGIN = -2,//入口
	BACKTRACKED = -1,//已经走过的路径
	AVAILABLE,//可通过
	WALL,//墙
	SPECIAL//特殊路径
};

点的移动

从入口处开始移动,同样使用Point来表示,因为点的移动需要方向,所以在Point中加入DIRECT表示方向。该点只用来移动Point中的stu信息是没用的,同样用来建立迷宫的点中direct信息也是没用的

方向信息
enum DIRECT
{
	RIGHT,//右
	DOWN,//下
	LEFT,//左
	UP,//上
	NOWAY//无路可走
};

Point

默认direct方向为右,stu状态为墙

struct Point
{
	Point(int xx = 0, int yy = 0, DIRECT dd = RIGHT,STATU ss = WALL){
		x = xx; y = yy; dir = dd; stu = ss;
	}
	Point(const Point&p){
		x = p.x;
		y = p.y;
		dir = p.dir;
		stu = p.stu;
	}
	Point& operator=(const Point&p){
		x = p.x;
		y = p.y;
		dir = p.dir;
		stu = p.stu;
		return *this;
	}
	int x;
	int y;
	DIRECT dir;
	STATU stu;

	bool operator==(const Point&p){
		return x == p.x&&y == p.y;
	}
	bool operator!=(const Point&p){
		return !(*this == p);
	}
};

建立迷宫

构建一个类maze表示迷宫,对于N阶段矩阵width, height都为N,因为考虑迷宫的边界问题,我们让迷宫的大小为N+2阶段矩阵,四周都用墙包起来,表示迷宫边界。

class maze{
public:
	maze(int width, int height){//
		this->m_width = width;
		this->m_height = height;
		m_maze = new Point*[width + 2];
		maze_creat();
		m_begin = getbegin();
		//从起始点开始移动 所以把起始点的状态设置为来过
		m_maze[m_begin.x][m_begin.y].stu = BACKTRACKED;
		m_end = getend();
	}
	int m_width;
	int m_height;
	Point **m_maze;
	Point m_begin;//起始点 
	Point m_end;//终点
public:
	void maze_creat();//迷宫创建函数
	void show();
	Point getbegin();//找到起始点
	Point getend();//找到终点
	void setstatu();//设置状态
	int min_route();//判断是否有通路
};

下面是创建迷宫的函数,手动输入迷宫信息,输入每一行的迷宫信息(0,1,-2,-3),输入必须合法 -2 -3只出现一次。

void maze::maze_creat(){//初始化迷宫  手动输入
//先把N+2的矩阵全部初始化为墙 
	for (int i = 0; i < m_width + 2; i++){
		m_maze[i] = new Point[m_height + 2]; 
		for (int j = 0; j < m_height + 2; j++){
			m_maze[i][j] = Point(i,j);
		}
	}
	//对输入的信息进行出来改变迷宫中对应点的状态
	for (int i = 1; i <= m_width; i++){
		for (int j = 1; j <= m_height ; j++){
			int s = 0;
			cin >> s;
			switch (s)
			{
			case 0:
				m_maze[i][j].stu = AVAILABLE;
				break;
			case 1:
				m_maze[i][j].stu = WALL;
				break;
			case 2: //用于特殊用途的点 该题不会用到
				m_maze[i][j].stu = SPECIAL;
				break;
			case -2:
				m_maze[i][j].stu = BEGIN;
				break;
			case -3:
				m_maze[i][j].stu = END;
				break;
			default:
				m_maze[i][j].stu = SPECIAL;
				break;
			}
		}
	}
}

在迷宫中找出口


  1. 可行,记录信息,入栈,否则
  2. 换方向尝试,可行1,不可行但还有其他方向2,否则3
  3. 回到栈顶的点,出栈,换方向移动,回到1
  4. 终止条件,找到终点 或者栈为空

从起点开始,每个点有4种移动的选择(右下左上),默认从右。操作1.对于每一次可行的移动,我们用辅助的栈将其信息记录,包括坐标以及移动方向操作2.因为默认总是从右开始移动,当向右不能移动时候(右边是墙,或者已经去过了)则换一个方向进行尝试。如果可行 操作1.记录坐标,方向,移动,如果不行,操作2.继续换方向尝试,直到所有方向都试过了仍然不能移动,说明当路径不是到达出口的路径,操作3则从栈中弹栈,找到上次移动的信息,然后操作2换一个方向尝试,可行 则操作1,不可行操作2,反复上面的操作。
终止条件
1.找到终点 返回真
2.从入口的四个方向全部尝试后,会将入口的信息出栈,此时栈为空,表示没有路径可行,返回假。

int maze::min_route(){
	stack<Point>s_mz;
	int row = 0;//用来表示下个点的x
	int col = 0;//用来表示下个点的y
	do
	{
		while (m_begin.dir !=NOWAY){ 
		//只有将四个方向全部试过或者到达终点才会跳出while
			row = m_begin.x;
			col = m_begin.y;
			switch (m_begin.dir)
			{
			case RIGHT:
				col = m_begin.y+1;
				break;
			case DOWN:
				row = m_begin.x+1;
				break;
			case LEFT:
				col = m_begin.y-1;
				break;
			case UP:
				row = m_begin.x-1;
				break;
			default:
				break;
			}
			//如果下一个点可行或者是终点
			if (m_maze[row][col].stu == AVAILABLE || m_maze[row][col].stu == SPECIAL || 
			m_maze[row]	[col].stu== END){
			//把当前点的信息入栈,坐标,移动方向
				s_mz.push(m_begin);
				//移动到下一个点
				m_begin.x = row; m_begin.y = col;
				//记得要将dir的信息改回默认的right	
				m_begin.dir = RIGHT;
				//改变达到点的状态为已经来过
				m_maze[row][col] = BACKTRACKED;
				if (m_begin == m_end){
				//到达终点
					cout << "ok" << endl;
					return 1;
				}
			}	
			else
			//当前方向不行,换方向,这里使用的++前面已经重载过了
				++m_begin.dir;
		}
		//回到上次移动的点
		m_begin = s_mz.top();
		//删除上次的移动信息
		s_mz.pop();
		//将上次移动的方向++,换下一个方向继续尝试
		++m_begin.dir;
	
	} while (!s_mz.empty());//栈空则终止,即入口不能到达出口 
	return 0;
}
发布了145 篇原创文章 · 获赞 12 · 访问量 9642

猜你喜欢

转载自blog.csdn.net/weixin_44997886/article/details/105034763