回溯法的使用是一种不断试探且及时纠正错误的搜索方法。下面的求解过程采用回溯法。从入口出发,按某一方向向前探索,若能走通(未走过的),即某处可以到达,则到达新点,否则试探下一方向 ; 若所有的方向均没有通路,则沿原路返回前一点,换下一个方向再继续试探,直到所有可能的通路都探索到,或找到一条通路,或无路可走又返回到入口点。
在求解过程中,为了保证在到达某一点后不能向前继续行走(无路)时,能正确返回前一点以便继续从下一个方向向前试探,则需要用一个栈保存所能够到达的每一点的下标及从该点前进的方向。
程序源码
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "malloc.h"
#define stack_size 1 //存储空间初始分配量
#define stack_add 1 //存储空间分配增量
#define error 0
#define ok 1
#define N 10
#define M 10
typedef int Elemtype;
typedef int Status;
/* 全局变量*/
int curstep=1; //当前足迹,初值为
//int map[5][4]={ //初始化迷宫地图
// {1,0,1,1},
// {1,0,0,1},
// {1,1,0,1},
// {1,1,0,0},
// {1,1,1,1}
// };
//起点[0,1] 终点[3,3] 找到路径
//起点[0,1] 终点[2,3] 没有找到路径
int map[M][N];
typedef struct // 迷宫坐标位置类型
{
int x; //行值
int y; //列值
}Post;
typedef struct{
int ord; //通道块在路径上的序号
Post seat; //通道块在迷宫中的"坐标位置"
int di; ;//从此通道块走向下一通道块的“东南西北方向"(1,2,3,4)//
}SElemType;
typedef struct{
SElemType *base; //在栈构造之前和销毁之后,base的值为null
SElemType *top; //栈顶指针
int stacksize; //当前已分配的存储空间,以元素为单位
}sql_stack;
sql_stack L;//定义全局变量的栈
//----------------栈的操作---------------
Status InitStack(sql_stack &L)//构造一个空栈
{
L.base=(SElemType *)malloc(stack_add*sizeof(SElemType));
if(!L.base)
exit(error);
L.top=L.base;
L.stacksize=stack_size;
return ok;
}
Status Push(sql_stack &L,SElemType e)//插入元素e为新的栈顶元素
{
if(L.top-L.base>=L.stacksize)
{
L.base=(SElemType *)realloc(L.base,(L.stacksize+stack_add)*sizeof(SElemType));
if(!L.base)
exit(error);
L.top=L.base+L.stacksize;
L.stacksize+=stack_add;
}
*L.top++=e;
return ok;
}
Status Pop(sql_stack &L,SElemType &e)//出栈
{
if(L.top==L.base)
return error;
e=*--L.top;
return ok;
}
Status StackEmpty(sql_stack L)//空栈条件
{
return (L.top==L.base);
}
//-----------迷宫路径操作------------
void MarkPrint(Post b)// 使迷宫m的b点的序号变为(不能通过的路径)
{
map[b.x][b.y]=1;
}
Status Pass(Post k) // 当迷宫m的k点的序号为(可通过路径),return ok; 否则,return error
{
if(map[k.x][k.y]==0)
return ok;
else
return error;
}
Post NextPos(Post c,int di)//根据当前位置及移动方向,返回下一位置
{
Post direc[4]={{0,1},{1,0},{0,-1},{-1,0}}; // {行增量,列增量}
// 移动方向,依次为右下左上
c.x+=direc[di].x;
c.y+=direc[di].y;
return c;
}
void FootPrint(Post o)//使迷宫m的o点的序号变为足迹(curstep)
{
map[o.x][o.y]=curstep;
}
Status Path(Post begin,Post end)
{
Post curpos;
SElemType e;
InitStack(L);
curpos=begin;
do
{
if(Pass(curpos))//当前位置可以通过,即是未曾走到过的通道块
{
FootPrint(curpos); //留下足迹
e.ord=curstep;
e.seat.x=curpos.x;
e.seat.y=curpos.y;
e.di=0;
Push(L,e);//入栈当前位置及状态
curstep++; // 足迹加
if(curpos.x==end.x&&curpos.y==end.y) // 到达终点(出口)
return ok;
curpos=NextPos(curpos,e.di);
}
else //当前位置不能通过
{
if(curpos.x==end.x&&curpos.y==end.y) // 没有出口
break;
if(!StackEmpty(L))
{
Pop(L,e); //退栈到前一位置
curstep--;
while(e.di==3&&!StackEmpty(L)) //前一位置处于最后一个方向(上)
{
MarkPrint(e.seat); //留下不能通过的标记(1)
Pop(L,e); // 退回一步
curstep--;
}
if(e.di<3) //没到最后一个方向(上)
{
e.di++; // 换下一个方向探索
Push(L,e);
curstep++;
curpos=NextPos(e.seat,e.di); // 设定当前位置是该新方向上的相邻块
}
}
}
}while(!StackEmpty(L));
return error;
}
int _tmain(int argc, _TCHAR* argv[])
{
Post begin,end;
SElemType e;
int x=0,y=0,count=0,m,n,mapresult[100];
printf("/t*******************迷宫算法********************/t/n/n");
printf("/n/t请输入迷宫的行数m=");
scanf("%d",&m);
printf("/n/t请输入迷宫的列数n=");
scanf("%d",&n);
printf("/n/t迷宫地图初始化:0代表通路,代表障碍,空格控制列间距,回车控制行换行/t/n/n");
for(int i=0;i<m;i++)
{
printf("/t ");
for(int j=0;j<n;j++)
scanf("%d",&map[i][j]);
}
printf("/n/t输入起点的横坐标,纵坐标[逗号隔开]/n");
printf("/n/t");
scanf("%d,%d",&begin.x,&begin.y);
printf("/n/t输入终点的横坐标,纵坐标[逗号隔开]/n");
printf("/n/t");
scanf("%d,%d",&end.x,&end.y);
if(Path(begin,end))
{
printf("/n/t此迷宫从入口到出口的路径如下:/n/n");
while(!StackEmpty(L))
{
Pop(L,e);
mapresult[count]=e.seat.x;
mapresult[++count]=e.seat.y;
count++;
}
printf("/t");
for(int i=count-1;i>=0;i=i-2)//输出路径
{
printf("[%d,%d] ",mapresult[i-1],mapresult[i]);
}
printf("/n/n");
}
else
{
printf("/n/t此迷宫没有从入口到出口的路径/n/n");
}
system("pause");
return 0;
}