1. 程式人生 > >一個簡單的迷宮演算法

一個簡單的迷宮演算法

迷宮問題的求解是一個典型的問題,那仫如何找到迷宮的出口?在遇到死衚衕的時候如何返回?如何防止走重複的路程?這就是我們要解決的問題了.

     一.設定迷宮

要列印一個簡單的迷宮,我們理所當然的想到了利用二維陣列,在迷宮的實現中我定義了一個MazeMap.txt的檔案用來儲存迷宮,在初始化的時候只需要將該迷宮從mazeMap.txt中讀出來就可以了.

       0-路

       1-牆

        

   二.如何找到迷宮的通路

  (1).如果當前路徑已經走過則要留下標記;如果走到死衚衕也要留下標記,但是要體現回溯,所以這兩種情況的標記最好不同

        (2).找迷宮路徑的可通路可理解為使用試探法.

        即在一個結點的上,下,左,右四個方向進行試探,如果某一個方向滿足迷宮位置要求則將該位置壓棧;如果走到死衚衕此時該位置的四個方向都不可通(之前已經將走過的路標記為2),我們只需要將該位置出棧即可.

        (3).判斷是否走出迷宮.

        因為迷宮的出口只可能在邊界,我們可以認為三個方向都可能存在出口.所以在判斷是否走出迷宮的時候,我們可以在除了入口的那一面都進行判斷.

        迷宮問題也是棧的應用場景之一

  三.實現場景.(體現回溯和找到迷宮出口)

     在迷宮中用到的棧是我自己寫的.

     

template<typename T>
class Stack
{
public:
	Stack()
		:_ptr(NULL)
		,_size(0)
		,_capacity(0)
	{}
	~Stack()
	{
		if(_ptr != NULL)
		{
			delete[]_ptr;
			_ptr=NULL;
		}
		_size=0;
		_capacity=0;
	}
	void Push(const T& x)
	{
		_CheckCapacity();
		_ptr[_size++]=x;
	}
	void Pop()
	{
		assert(_size >= 0);
		_size--;
	}
	bool Empty()
	{
		return _size == 0;
	}
	T& Top()
	{
		return _ptr[_size-1];
	}
	size_t Size()
	{
		return _size;
	}
protected:
	void _CheckCapacity()
	{
		if(_size == _capacity)
		{
			int NewCapacity=2*_capacity+2;
			T *tmp=new T[NewCapacity];
			//memcpy(tmp,_ptr,_size*sizeof(T));
			for(int i=0;i<_size;i++)
			{
				tmp[i]=_ptr[i];
			}
			delete []_ptr;
			_ptr=tmp;
			_capacity=NewCapacity;
		}
	}
protected:
	T *_ptr;
	int _size;
	int _capacity;
};

     實現迷宮的基本演算法.

const int N=10;

struct Pos
{
	Pos(int row=0,int col=0)
		:_row(row)
		,_col(col)
	{}
	int _row;   //行
	int _col;   //列
};

void InitMaze(int *mz)
{
	char tmp;
	Pos enter;
	FILE *pf=fopen("MazeMap.txt","r");
	assert(pf);
	for(size_t i=0;i<N;++i)
	{
		for(size_t j=0;j<N;)
		{
			tmp=fgetc(pf);
			if(tmp == '0' || tmp == '1')
			{
				mz[i*N+j]=tmp-'0';
				++j;
			}
		}
	}
}

bool CheckReason(int *mz,Pos pos)
{
	if((pos._row >= 0) && (pos._col < N) && 
		(pos._row >= 0) && (pos._col < N) && 
		(mz[pos._row*N+pos._col] == 0))
	{
		return true;  //可通路
	}
	return false;     //不可通路
}

bool FindPath(int *mz,int rows,int cols,Stack<Pos>& s,Pos enter)
{
	s.Push(enter);
	mz[enter._row*cols+enter._col]=2;
	while(!s.Empty())     //如果棧為空說明該迷宮無解
	{
		Pos cur=s.Top();
		Pos next=cur;
		if((next._row == 0) || (next._row == rows-1) || (next._col == cols-1))
			//判斷是否走出迷宮
		{
			return true;
		}
		//上
		next._row  -= 1;
		if(CheckReason((int *)mz,next))
		{
			s.Push(next);
			mz[next._row*cols+next._col]=2;   //經過的路置標記,防止走回頭路
			continue;
		}
		next._row += 1;
		//右
		next._col += 1;
		if(CheckReason((int *)mz,next))
		{
			s.Push(next);
			mz[next._row*cols+next._col]=2;
			continue;
		}
		next._col -= 1;
		//左
		next._col -= 1;
		if(CheckReason((int *)mz,next))
		{
			s.Push(next);
			mz[next._row*cols+next._col]=2;
			continue;
		}
		next._col += 1;
		//下
		next._row += 1;
		if(CheckReason((int *)mz,next))
		{
			s.Push(next);
			mz[next._row*cols+next._col]=2;
			continue;
		}
		next._row  -= 1;

		mz[cur._row*cols+cur._col]=3;   //體現回溯
		s.Pop();
	}
	return false;
}

void PrintMaze(int *mz)
{
	for(size_t i=0;i<N;i++)
	{
		for(size_t j=0;j<N;j++)
		{
			cout<<mz[i*N+j]<<" ";
		}
		cout<<endl;
	}
	cout<<endl;
}

  在此迷宮問題中也可以找到走出此迷宮的最優路徑,在這裡用到圖的廣度優先可以解決...