迷宫问题

问题描述:给定一个M X N的迷宫图,求一条从指定入口的到出口的路径

数据组织:为了表示迷宫,设置一个二维数组(migong) mg[ M][N] ,其中数组的每个元素表示一个方块的状态,0表示对应的方块为通道,1表示对应方块是墙。为了算法方便,在迷宫外面加一道墙,所以二维数组表示演变如下:(假设M=8,N=8)

mg[M+2][N+2]=                                                                                     

 	{	
	 {1,1,1,1,1,1,1,1,1,1},                		                  
	 {1,0,0,1,0,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+1,j),接着试探到(i,j),这样就是引起死循环,为此,在一个方块进栈后,将对应mg数组元素值改为-1,表示该方块为不可走相邻方块,当该方块退栈时,将其恢复为0

下面代码是给出找到一条路径的算法:

#include <iostream>
using namespace std;
#define MaxSize 100 
#define M 8   //行数
#define N 8   //列数

int mg[M+2][N+2] = {
		  	{1,1,1,1,1,1,1,1,1,1},
			{1,0,0,1,0,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}
		   }; 

typedef struct 
{
	int row;   //当前方块的行号
	int column;   //当前方块的列号
	int direction ;   //下一个可走的方格的方位编号 0:上 1:右  2:下 3:左
}Box;  //定义方块类型

typedef struct
{
	Box data[MaxSize] ;
	int top ;     //栈顶指针
}StackType ;  //定义顺序栈类型

bool mgpath(int startRow,int startColumn,int endRow,int endColumn)
{
	int i,j,k,direction,find;
	StackType stackType ;
	stackType.top = -1 ;
	stackType.top++;
	stackType.data[stackType.top].row = startRow ;
	stackType.data[stackType.top].column=startColumn;
	stackType.data[stackType.top].direction = -1 ;
	mg[startRow][startColumn]= -1 ;
	//栈不为空时循环
	while(stackType.top > -1)
	{
		i=stackType.data[stackType.top].row;
		j=stackType.data[stackType.top].column;
		direction =stackType.data[stackType.top].direction;  
		//取栈顶方块
		if(i==endRow && j==endColumn)
		{
			cout<<"迷宫路径如下"<<endl;
			for(k=0;k<=stackType.top;k++)
			{
				cout<<"("<<stackType.data[k].row<<","<<stackType.data[k].column<<")	" ;
				if((k+1)%5 == 0)
					cout<<endl;
			}
			cout<<endl;
			return true ;		
		}
		find = 0 ;
		//找下一个可走的方块
		while(direction < 4 && find==0)
		{
			direction++;
			switch(direction)
			{
				case 0 : 
					i=stackType.data[stackType.top].row-1;
					j=stackType.data[stackType.top].column;
					break;
				case 1 :
					i=stackType.data[stackType.top].row;
					j=stackType.data[stackType.top].column+1;
					break;
				case 2:
					i=stackType.data[stackType.top].row+1;
					j=stackType.data[stackType.top].column;
					break;
				case 3:
					i=stackType.data[stackType.top].row;
					j=stackType.data[stackType.top].column-1;
					break;
			}
			if(mg[i][j] == 0)
				find = 1 ;       //找到下一个可走的相邻方块
		}
		//找到下一个可走方块
		if(find == 1)
		{
			stackType.data[stackType.top].direction=direction ;
			stackType.top++;
			stackType.data[stackType.top].row=i ;
			stackType.data[stackType.top].column=j ;
			stackType.data[stackType.top].direction = -1 ;
			mg[i][j]=-1;

		}
		else
		{
			//没有路径可走,则退栈
			mg[stackType.data[stackType.top].row][stackType.data[stackType.top].column] = 0 ;
			stackType.top--;
		}
	}
	return false;
}

int main()
{

	if(!mgpath(1,1,M,N))
		cout<<"该迷宫问题没有解!"<<endl;
	cout<<"结束"<<endl;
	return 0 ;
}

运行结果如下:



拓展:输出所有能从入口到出口的的路径和其中最短路径

代码如下:

#include <iostream>
using namespace std;
#define MaxSize 100    
#define M 8   //行数
#define N 8   //列数

int mg[M+2][N+2] = {
			{1,1,1,1,1,1,1,1,1,1},
			{1,0,0,1,0,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}
		   }; 

typedef struct 
{
	int row;   //当前方块的行号
	int column;   //当前方块的列号
	int direction ;   //下一个可走的方格的方位位编号 0:上 1:右  2:下 3:左
}Box;  //定义方块类型

typedef struct
{
	Box data[MaxSize] ;
	int top ;     //栈顶指针
}StackType ;  //定义顺序栈类型

void mgpath(int startRow,int startColumn,int endRow,int endColumn)
{
	int i,j,k,direction,find;
	int count=1;            //路径数计数  
	int minlen=MaxSize;     //最短路径长度  
	StackType path;
	StackType stackType ;
	stackType.top = -1 ;
	stackType.top++;
	stackType.data[stackType.top].row = startRow ;
	stackType.data[stackType.top].column=startColumn;
	stackType.data[stackType.top].direction = -1 ;
	mg[startRow][startColumn]= -1 ;
	//栈不为空时循环
	while(stackType.top > -1)
	{
		i=stackType.data[stackType.top].row;
		j=stackType.data[stackType.top].column;
		direction =stackType.data[stackType.top].direction;  
		//取栈顶方块
		if(i==endRow && j==endColumn)
		{
			count++;   //路径树基数
			cout<<"迷宫路径如下"<<endl;
			for(k=0;k<=stackType.top;k++)
			{
				cout<<"("<<stackType.data[k].row<<","<<stackType.data[k].column<<")	" ;
				if((k+1)%5 == 0)
					cout<<endl;
			}
			cout<<endl<<endl;
			//因为空栈top=-1,当栈里面有元素是为top=0,1,2,3,4...MaxSize-1 ,总共有MaxSize个元素
			//所以stackType.top+1为栈里面的元素个数
			if(stackType.top+1<minlen)
			{       
				//比较输出最短路径  
                for(k=0;k<=stackType.top;k++)
				{
					path.data[k]= stackType.data[k];
				}
                minlen=stackType.top+1;  
            }
			//让该位置变为其他路径的可走结点 
			mg[stackType.data[stackType.top].row][stackType.data[stackType.top].column] = 0 ;    
            stackType.top--;  
			i=stackType.data[stackType.top].row;
			j=stackType.data[stackType.top].column;
			direction= stackType.data[stackType.top].direction;  		
		}
		find = 0 ;
		//找下一个可走的方块
		while(direction < 4 && find==0)
		{
			direction++;
			switch(direction)
			{
				case 0 : 
					i=stackType.data[stackType.top].row-1;
					j=stackType.data[stackType.top].column;
					break;
				case 1 :
					i=stackType.data[stackType.top].row;
					j=stackType.data[stackType.top].column+1;
					break;
				case 2:
					i=stackType.data[stackType.top].row+1;
					j=stackType.data[stackType.top].column;
					break;
				case 3:
					i=stackType.data[stackType.top].row;
					j=stackType.data[stackType.top].column-1;
					break;
			}
			if(mg[i][j] == 0)
				find = 1 ;       //找到下一个可走的相邻方块
		}
		//找到下一个可走方块
		if(find == 1)
		{
			stackType.data[stackType.top].direction=direction ;
			stackType.top++;
			stackType.data[stackType.top].row=i ;
			stackType.data[stackType.top].column=j ;
			stackType.data[stackType.top].direction = -1 ;
			mg[i][j]=-1;

		}
		else
		{
			//没有路径可走,则退栈
			mg[stackType.data[stackType.top].row][stackType.data[stackType.top].column] = 0 ;
			stackType.top--;
		}
	}
	
	cout<<"最短路径如下:"<<endl;
	cout<<"长度:"<<minlen<<endl;
	cout<<"路径:"<<endl; 
    for(k=0;k<minlen;k++){  
        cout<<"("<<path.data[k].row<<","<<path.data[k].column<<")	" ;
        if((k+1)%5==0)      //输出时每5个结点换一行  
           cout<<endl;
    }  
    cout<<endl;
}

int main()
{

	mgpath(1,1,M,N);
	cout<<"结束"<<endl;
	return 0 ;
}

程序运行结果:




........................................................................................

.......................................................................................

.......................................................................................



读者可能会奇怪,为什么就能确定遍历完所有路径?

大家仔细想想,我每个方块按照(不包括边框的方块墙,我们自己加上去的)按照上、右、下、左的方向进行遍历(代码中direction代表方向),也就是说,所走的方块上下左右我都遍历完了。假设我们可以走的方块数目为W个,我们实际上遍历了4的W次方条可能路径,在进行剪枝操作,选取可行的路径。

第一个可行方块的遍历顺序为,上,右,下,左。如果第一个可行方块的上边有可行方块,我们将选取1第一方块的上面方块做为第二可行方块;如果第一方块上边没有可行方块,将找第一方块的右方块,如果是可行方块,将第一方块的有方块做为第二行方块,;如果第一方块的上,右没有可能方块,将遍历第一方块的下方块,如果还不是可行方块,将遍历第一方块的左方块,以此找到第二方块,第三方块.....

(此思路和递归雷同,相同的案例有:八皇后)






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值