回溯法-迷宮問題

迷宮問題中,在尋找路徑時,採用的方法通常是:從入口出發,沿某一方向向前試探,若能走通,則繼續向前進;如果走不通,則要沿原路返回,換一個方向再繼續試探,直到所有可能的能跟都試探完成爲止。爲了保證在任何位置上都能沿原路返回(回溯),要建立一個後進先出的棧來保存從入口到當前位置的路徑。

   而且在求解迷宮路徑中,所求得的路徑必須是簡單路徑。即在求得的路徑上不能有重複的同一塊通道。

   爲了表示迷宮,設置一個數組,其中每個元素表示一個方塊的狀態,爲0時表示對應方塊是通道,爲1時表示對應方塊爲牆,數組如下所示:

 

int mg[10][10] = {      //定義一個迷宮,0表示通道,1表示牆
	{1,1,1,1,1,1,1,1,1,1},
	{1,0,0,1,1,0,0,1,0,1},
	{1,0,0,1,0,0,0,1,0,1},
	{1,0,0,0,0,1,1,0,0,1},
	{1,0,1,1,1,0,0,0,0,1},
	{1,0,0,0,1,0,0,0,0,1},
	{1,0,1,0,0,0,1,0,0,1},
	{1,0,1,1,1,0,1,1,0,1},
	{1,1,0,0,0,0,0,0,0,1},
	{1,1,1,1,1,1,1,1,1,1}};


對於迷宮中每個方塊,都有上下左右四個方塊相鄰,第i行第j列的當前方塊的位置爲(i,j),規定上方方塊爲方位0,按順時針方向遞增編號。假設從方位0到方位3的方向查找下一個可走方塊。

      爲便於回溯,對於可走的方塊都要進棧,並試探它的下一個可走方位,將這個可走的方位保存到棧中,棧定義如下:

struct St                //定義一個棧,保存路徑
{
	int i;               //當前方塊的行號
	int j;               //當前廣場的列號
	int di;              //di是下一可走方位的方位號
} St[MaxSize];           //定義棧


求解路徑過程爲:先將入口進棧(初始方位設置爲-1),在棧不爲空時循環:取棧頂方塊(不退棧),若是出口,則輸出棧中方塊即爲路徑。否則,找下一個可走的相鄰方塊,若不存在這樣的方塊,則退棧。若存在,即將其方位保存到棧頂元素中,並將這個可走相鄰方塊進棧(初始方位設置爲-1)。

      爲保證試探可走相鄰方塊不是已走路徑上的方塊,如(i,j)已經進棧,在試探(i+1,j)的下一可走方塊時,又試探到(i,j),這樣會引起死循環,爲此,在一個方塊進棧後,將對應的mg數組元素值改爲-1(變爲不可走),當退棧時(沒有可走的相鄰方塊),將其恢復爲0.

      算法如下:

#include <iostream>      
#include <iomanip>  
#include <stdlib.h>
using namespace std; 


#define MaxSize 100

int mg[10][10] = {      //定義一個迷宮,0表示通道,1表示牆
	{1,1,1,1,1,1,1,1,1,1},
	{1,0,0,1,1,0,0,1,0,1},
	{1,0,0,1,0,0,0,1,0,1},
	{1,0,0,0,0,1,1,0,0,1},
	{1,0,1,1,1,0,0,0,0,1},
	{1,0,0,0,1,0,0,0,0,1},
	{1,0,1,0,0,0,1,0,0,1},
	{1,0,1,1,1,0,1,1,0,1},
	{1,1,0,0,0,0,0,0,0,1},
	{1,1,1,1,1,1,1,1,1,1}};

struct St                //定義一個棧,保存路徑
{
	int i;               //當前方塊的行號
	int j;               //當前廣場的列號
	int di;              //di是下一可走方位的方位號
} St[MaxSize];           //定義棧

int top = -1;            //初始化棧指針

void MgPath(int xi, int yi, int xe, int ye)            //路徑爲從(xi,yi)到(xe,ye)
{
	int i, j, di, find, k;
	top++;                                             //初始方塊進棧
	St[top].i = xi;St[top].j = yi;St[top].di = -1;
	mg[xi][yi] = -1;
	while(top>-1)                                      //棧不爲空時循環
	{
		i = St[top].i;j = St[top].j;di = St[top].di;
		if(i==xe && j==ye)                             //找到了出口,輸出路徑
		{
			cout << "迷宮路徑如下:/n";
			for(k=0; k<=top; k++)
			{
				cout << "/t(" << St[k].i << "," << St[k].j << ")";
				if((k+1)%5==0) cout << endl;            //每輸出五個方塊後換一行
			}
			cout << endl;
			return;
		}
		find = 0;
		while(di<4 && find==0)                          //找下一個可走方塊
		{
			di++;
			switch(di)
			{
			case 0:i = St[top].i-1; j = St[top].j; break;
			case 1:i = St[top].i; j = St[top].j+1; break;
			case 2:i = St[top].i+1; j = St[top].j; break;
			case 3:i = St[top].i; j = St[top].j-1; break;
			}
			if(mg[i][j]==0) find = 1;                      //找到通路
		}
		if(find==1)                                        //找到了下一個可走方塊
		{
			St[top].di = di;                               //修改原棧頂元素的di值
			top++;                                         //下一個可走方塊進棧
			St[top].i = i; St[top].j = j; St[top].di = -1;
			mg[i][j] = -1;                                 //避免重複走到這個方塊
		}
		else                                               //沒有路可走,則退棧
		{
			mg[St[top].i][St[top].j] = 0;                  //讓該位置變成其它路徑可走方塊
			top--;
		}
	}
	cout << "沒有可走路徑!/n";
}

int main()
{
	MgPath(1,1,8,8);
}


 


 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章