1. 程式人生 > >回溯法求迷宮問題

回溯法求迷宮問題

回溯法(探索與回溯法)是一種選優搜尋法,又稱為試探法,按選優條件向前搜尋,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀態的點稱為“回溯點”。
本文使用回溯法求解迷宮問題
迷宮問題,有一個m行n列的矩陣代表迷宮,1代表此路不通,0代表此路通。指定入口和出口,判斷是否能從入口進,從出口走出。此程式只判斷從路口到出口是否能走通,找到的路不一定是最短路(最短路的程式在下一篇中使用BFS演算法給出),注意:從入口到出口可能沒有路徑或者不止一條路徑。此處迷宮走法是8個方向,分別是左上,上,右上,右,右下,下,左下,左。程式中使用offsets myMove給出八個方向的表示。
#include <iostream>
#include <stack>
using namespace std;


struct offsets 
{
	int a,b;//a,b是x,y方向的偏移
	char* dir;//dir方向
};
offsets myMove[8] = {//各個方向的偏移表
	{-1,0,"N"},
	{-1,1,"NE"},
	{0,1,"E"},
	{1,1,"SE"},
	{1,0,"S"},
	{1,-1,"SW"},
	{0,-1,"W"},
	{-1,0-1,"NW"}
	
};
struct items 
{
	int x,y,dir;//位置和前進方向的序號
};
const int MAXNUM = 5;
int mark[MAXNUM][MAXNUM] = {0};//標記陣列
int Maze[MAXNUM][MAXNUM] = {
	1,1,1,1,1,
	1,0,1,0,1,
	1,0,0,1,1,
	1,1,1,0,1,
	1,1,1,1,1
}; //迷宮

void printPath(stack<items>& st)
{
	int num = st.size(); 
	for (int index = 0; index < num; index++)
	{
		items tmpIt = st.top();
		cout<<"("<<tmpIt.x<<","<<tmpIt.y<<","<<tmpIt.dir<<")"<<"<-";
		st.pop();
	}
	cout<<endl;
}
void Mypath(int m,int p)
{
	int flag = 0;
	int Currx,Curry,Currd,Searchx,Searchy;
	mark[1][1] = 1;//(1,1)是入口
	stack<items> st;
	items tmp;
	tmp.x = 1,tmp.y = 1,tmp.dir = 2;
	st.push(tmp);
	while (! st.empty())
	{
		if (flag == 1)
		{
			st.pop();
		}
		flag = 0;
		items tmpItems = st.top();
		Currx = tmpItems.x,Curry = tmpItems.y,Currd = tmpItems.dir;
		while (Currd < 8)
		{
			Searchx = Currx + myMove[Currd].a,Searchy = Curry + myMove[Currd].b;
			
			if (Maze[Searchx][Searchy] == 0 && mark[Searchx][Searchy] == 0)
			{
				flag = 1;
				mark[Searchx][Searchy] = 1;
				tmp.x = Searchx,tmp.y = Searchy,tmp.dir = Currd;
				st.push(tmp);
				Currx = Searchx;Curry = Searchy; Currd = 0;
			}
			else
			{
				Currd++;
			}
			if (Searchx == m && Searchy == p)
			{
				cout<<m<<" "<<p<<endl;
				cout<<"("<<m<<","<<p<<","<<Currd<<")"<<"<-";
				printPath(st);

				return;
			}
			
			
		}
		
	}
	cout<<"no path in Maze"<<endl;
}

int main()
{
	Mypath(2,1);
}