走出这个迷宫

       求解迷宫路径是一个典型的问题,通常我们都是用 栈+回溯法+试探法 来解决这个问题。下面为大家介绍一下怎样用栈怎样找出迷宫的路径 。

在实现代码之前我们先来分下一下:

1、迷宫地图的设置

       我们可以把迷宫地图存到文本里面,当需要的时候我们在重文本里面读取。因为迷宫的大小不确定,所以我们要动态开辟二维数组来存放地图。


如图:在第一行我们要存迷宫的 

行  列  入口的横坐标 入口的纵坐标

接下来就是迷宫的地图。


2、如果当前坐标我们已经走过了,则要给予标记,也就是留下足迹。如果当前路径不通,那我们也要留下不通的标记。


3、求解路径的基本思想是:如果当前路径能通过,在将当前路径压栈,并做标记;然后回溯,读取下一个坐标再试探,如果不能通,则留下不能通过的标记,并把这个坐标出栈。


#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cassert>

using namespace std;


typedef struct NodePos
{
	int x;
	int y;
	NodePos(int row=0, int col=0)
		:x(row)
		, y(col){}
}Node;


//因为迷宫用的栈 是我自己的,为了方便验证,我将栈也给出
template<typename T>
class Stack
{
public:
	Stack()
		:_capacity(0)
		, _size(0)
		, _ptr(NULL)
	{}
	~Stack()
	{
		delete[] _ptr;
		_size = 0;
		_capacity = 0;
		_ptr = NULL;
	}
	void Push(const T& data);
	void Pop();
	T Top();
	int Size();
	bool Empty();
private:
	void CheckCapacity()
	{
		if (_size >= _capacity)
		{
			int NewCapacity = _capacity * 2 + 1;
			T* tmp = new T[NewCapacity];
			for (int i = 0; i < _size; i++)
			{
				tmp[i] = _ptr[i];
			}
			delete[] _ptr;
			_ptr = tmp;
			_capacity = NewCapacity;
		}
	}
private:
	T* _ptr;
	int _capacity;
	int _size;
};

template<typename T>
bool Stack<T>::Empty()
{
	if (_size == 0)
		return true;
	else
		return false;
}

template<typename T>
void Stack<T>::Push(const T& data)
{
	CheckCapacity();
	_ptr[_size++] = data;
}

template<typename T>
void Stack<T>::Pop()
{
	assert(_size>0);
	--_size;
}

template<typename T>
T Stack<T>::Top()
{
	return _ptr[_size - 1];
}

template<typename T>
int Stack<T>::Size()
{
	return _size;
}

//下面用到的栈是自己实现的栈
template<typename T>
class Maze
{
	typedef Node Pos;
public:
	Maze()
		:_row(0)
		, _col(0)
		, _start(0,0)
		, _map(NULL)
	{}
	~Maze()
	{
		for (int i = 0; i < _row; i++)
		{
			delete[] _map[i];
		}
		delete[] _map;
	}
	bool SearchPath();            //查找迷宫路径
	void PrintMap();              //输出迷宫地图
	void PrintPath();             //打印路径的坐标
	void SetMap();                //设置地图
private:
	bool CheckNextAccess(Pos coor);        //判断该坐标能否通过
private:
	int _row;
	int _col;
	T **_map;
	Stack<Pos> _s;
	Pos _start;
};

template<typename T>
bool Maze<T>::CheckNextAccess(Pos coor)    //判断该坐标能否通过
{
	if (coor.x >= 0 && coor.x < _row
		&&coor.y >= 0 && coor.y < _col
		&&_map[coor.x][coor.y] == 0)           //判断是否越界
	{
		return true;
	}
	else
	{
		return false;
	}
}


template<typename T>
void Maze<T>::SetMap()
{
	char c;
	FILE *fp = fopen("MazeMap.txt", "r");      //打开文件读取地图
	assert(fp);
	//读取行
	while ((c = getc(fp))!= ' '&&c != '\n')
	{
		_row=_row*10+(c-'0');
	}
	//读取迷宫列
	while ((c = getc(fp)) != ' '&&c != '\n')
	{
		_col=_col*10+(c - '0');
	}
	//读取迷宫入口横坐标
	while ((c = getc(fp)) != ' '&&c != '\n')
	{
		_start.x = _start.x*10+(c - '0');
	}
	//读取迷宫入口纵坐标
	while ((c = getc(fp)) != ' '&&c != '\n')
	{
		_start.y = _start.y*10+(c - '0');
	}
	//开辟迷宫数组
	_map = new T*[_row];
	for (int i = 0; i < _row; i++)
	{
		_map[i] = new T[_col];
	}

	//读取迷宫地图
	for (int i = 0; i < _row; i++)
	{
		for (int j = 0; j < _col;)
		{
			c = getc(fp);
			if (c == '1' || c == '0')
			{
				_map[i][j] = c - '0';
				j++;
			}
		}
	}
	fclose(fp);     //关闭文件
}



template<typename T>
bool Maze<T>::SearchPath()
{
	Pos cur = _start;
	_s.Push(_start);                   //将起点坐标压入栈
	_map[_start.x][_start.y] = 2;      //走过的路径设置为2
	while (!_s.Empty())                //如果栈以空,则说明又回到入口,则迷宫无解
	{
		Pos next=_s.Top();
		cur = next;
		_map[cur.x][cur.y] = 2;           //将坐标设置为已走过
		if (next.x==_row-1||next.y==_col-1)     //判断是否走到出口
		{
			return true;
		}
		//上
		next.x--;
		if (CheckNextAccess(next))  //如果当前坐标能够通过,则加入坐标
		{
			_s.Push(next);
			continue;
		}
		next.x++;

		//下
		next.x++;
		if (CheckNextAccess(next))
		{
			_s.Push(next);
			continue;
		}
		next.x--;

		//左
		next.y--;
		if (CheckNextAccess(next))
		{
			_s.Push(next);
			continue;
		}
		next.y++;

		//右
		next.y++;
		if (CheckNextAccess(next))
		{
			_s.Push(next);
			continue;
		}

		_s.Pop();                     //如果当前坐标不通,则退栈
		_map[next.x][next.y]= 3;      //并将这个坐标标记为不通
	}
	return false;
}

template<typename T>
void Maze<T>::PrintMap()       //打印迷宫地图,但是必须先设置迷宫地图
{
	for (int i = 0; i < _row; i++)
	{
		for (int j = 0; j < _col; j++)
		{
			cout << _map[i][j] <<" ";
		}
		cout << endl;
	}
}

template<typename T>
void Maze<T>::PrintPath()          //打印迷宫路径
{
	Stack<Pos> coor;
	while (!_s.Empty())
	{
		coor.Push(_s.Top());
		_s.Pop();
	}
	while (!coor.Empty())
	{
		cout << "(" << coor.Top().x << "," << coor.Top().y << ")" << endl;
		coor.Pop();
	}
}


void test()
{
	Maze<int> m;
	m.SetMap();                          //先设置地图
	m.PrintMap();
	cout << (m.SearchPath() == 1 ? "Yes":"NO") << endl;
	m.PrintMap();
	m.PrintPath();
}
int main()
{
	test();
	system("pause");
	return 0;
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值