用栈和递归解决迷宫问题

今天讲的是一个关于迷宫的面试题,首先咱们先看一下他的简单版本,模型如下图:


利用递归把问题简单化,找入口到出口的问题可以转化为从入口四周的合法的点到出口的问题,一旦找到就结束整个递归,在找的同时,把能走的路压到一个栈里面,然后探测四周,如果四周都不能走就退栈,如果某一个方向能走,进行压栈,然后转尔探测新的坐标的四周,代码如下:

#include<iostream>
#include<stack>
using namespace std;
struct Set
{
	Set(int x, int y) :_x(x), _y(y)
	{}
	int _x;
	int _y;
};
//找一条路

template<int MAX>
class Mez
{
public:
	//初始化迷宫
	Mez(int arr[][MAX])
	{
		maparr = new int[MAX][MAX];
		for (int i = 0; i < MAX; i++)
		{
			for (int j = 0; j < MAX; j++)
			{
				maparr[i][j] = arr[i][j];
			}
		}
	}
	~Mez()
	{
		delete[] maparr;
	}
	void display()
	{
		for (int i = 0; i < MAX; i++)
		{
			for (int j = 0; j < MAX; j++)
			{
				printf("%4d", maparr[i][j]);
			}
			cout << endl << endl;
		}
		cout << endl;
	}
	bool  movement(Set&set, stack<Set>& Route)
	{
		if (Islegalset(set))
		{
			maparr[set._x][set._y] = 2;
			Route.push(set);
			if (Iswill(set))
			{
				return true;
			}
			//如果他的下一个位置为0则可以走。
			//朝上走
			if (maparr[set._x - 1][set._y] == 0)
			{
				if(movement(Set(set._x - 1, set._y), Route))
					return true;
			}
			//朝左走
			if (maparr[set._x][set._y - 1] == 0)
			{
				if(movement(Set(set._x, set._y - 1), Route))
					return true;
			}
			//朝右走
			if (maparr[set._x][set._y + 1] == 0)
			{
				if(movement(Set(set._x, set._y + 1), Route))
					return true;
			}
			//朝下走
			if (maparr[set._x + 1][set._y] == 0)
			{
				if (movement(Set(set._x + 1, set._y), Route))
					return true;
			}
			//如果周围的路都不通,把这个坐标pop出来,交给他的上一级调用者,继续探测周围。
			Route.pop();
			//把不通的路标记为3(也可以不标记)
			maparr[set._x][set._y] = 3;
		}
		return false;
	}
	bool Islegalset(const Set&set)
	{
		if (0 <= set._x&&set._x < MAX && 0 <= set._y&&set._y < MAX)
		{
			return true;
		}
		return false;
	}
	bool Iswill(const Set& set)
	{
		if (set._x == 0 || set._y == 0 || set._y == MAX - 1)
		{
			cout << "出口为:" << set._x << " " << set._y << endl;
			return true;
		}
		return false;
	}
private:
	int(*maparr)[MAX];
};

int main()
{
	int arr[11][11] = {
		{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 },
		{ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 }
	};
	Mez<11> mez(arr);
	mez.display();
	//保存走的通路
	stack<Set>Route;
	mez.movement(Set(10, 6), Route);
	mez.display();
	return 0;
}

运行结果如下图:


上面只是一种简单形式的迷宫,假如迷宫有多条出路,要求走完所有出路,如图:

此时我们就不能在找到一条路时立马结束整个递归了程序,而是要遍历完四周所有能走的路时才可以结束程序,代码如下:

#include<iostream>
#include<stack>
using namespace std;
struct Set
{
	Set(int x, int y) :_x(x), _y(y)
	{}
	int _x;
	int _y;
};
template<int MAX>
class Mez
{
public:
	//初始化迷宫
	Mez(int arr[][MAX])
	{
		maparr = new int[MAX][MAX];
		for (int i = 0; i < MAX; i++)
		{
			for (int j = 0; j < MAX; j++)
			{
				maparr[i][j] = arr[i][j];
			}
		}
	}
	~Mez()
	{
		delete[] maparr;
	}
	void display()
	{
		for (int i = 0; i < MAX; i++)
		{
			for (int j = 0; j < MAX; j++)
			{
				printf("%4d", maparr[i][j]);
			}
			cout << endl << endl;
		}
		cout << endl;
	}
	void  movement(Set&set, stack<Set>& Route, stack<stack<Set>>&stackRoute)
	{

		if (Islegalset(set))
		{
			maparr[set._x][set._y] = 2;
			
			if (maparr[set._x][set._y] == 1)
			{
				return;
			}
			Route.push(set);
			if (Iswill(set))
			{
				//把所有的通路保存起来
				stackRoute.push(Route);
				//如果找到一条通路,在处理完之后把最后一个元素pop掉,把递归返回到他的上一级调用者,继续探测
				Route.pop();
				return;
			}
			//如果他的下一个位置为0则可以走。
			//朝上走
			if (maparr[set._x - 1][set._y] == 0 )
			{
				movement(Set(set._x - 1, set._y), Route, stackRoute);
			}
			//朝左走
			if (maparr[set._x][set._y - 1] == 0)
			{
				movement(Set(set._x, set._y - 1), Route, stackRoute);
			}
			//朝右走
			if (maparr[set._x][set._y + 1] == 0 )
			{
				movement(Set(set._x, set._y + 1), Route, stackRoute);
			}
			//朝下走
			if (maparr[set._x + 1][set._y] == 0 )
			{
				movement(Set(set._x + 1, set._y), Route, stackRoute);
			}
			//如果所以的路都不通,把这个坐标pop出来,交给他的上一级调用者,继续探测周围。
			Route.pop();
		}
	}
	bool Islegalset(const Set&set)
	{
		if (0 <= set._x&&set._x < MAX && 0 <= set._y&&set._y < MAX)
		{
			return true;
		}
		return false;
	}
	bool Iswill(const Set& set)
	{
		if (set._x == 0 || set._y == 0 || set._y == MAX - 1)
		{
			cout << "出口为:" << set._x << " " << set._y << endl;
			return true;
		}
		return false;
	}
private:
	int(*maparr)[MAX];
};

int main()
{
	int arr[11][11] = {
		{ 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
		{ 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 },
		{ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1 },
		{ 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 }
	};
	Mez<11> mez(arr);
	mez.display();
	//保存所有的通路
	stack<stack<Set>>ArrayRoute;
	//每次走的通路
	stack<Set>Route;
	mez.movement(Set(10, 6), Route,ArrayRoute);
	mez.display();
	printf("总共有%d条通路\n", ArrayRoute.size());
	return 0;
}

运行结果如下图:

如图所示,我们创建了一个栈专门保存所有的通路,而且也遍历完了所有的通路,但是这个也有一个问题,当里面存在环的时候,让你求迷宫里面的最短路问题,这样的标记就会出现错误,如下图:

运行结果如图:

以上就是关于迷宫的三个版本,如果有不对的地方,还请多多指教。。







  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值