迷宫问题是一个经典的问题,当迷宫规模较大时,手工求解是十分困难的,所以用善于进行重复繁琐计算的计算机来求解便十分合适。基本思想和解决“八皇后问题” 的思想一致,都是利用回溯法。从入口开始,探索每一个迷宫中没有被墙挡住的位置,如果该位置可以移动到下一个位置,则标记该位置已被探索过并入栈;如果不能移动到下一位置,则标记为探索失败并回退到上一个位置,如果最终退回了出发点,则说明迷宫无解。下面附上代码:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define passed 2
#define failed 3
#define N 2//定义迷宫规模
#define NUM (N+2)//定义迷宫总宽度
/*迷宫中为1的地方为墙壁,0为可到达的点*/
typedef int status;
typedef int elemtype;
/*定义位置pos*/
typedef struct pos{
elemtype x;
elemtype y;
elemtype next;//当前位置的下一个位置
}pos;
typedef struct sqstack{
pos p[N*N];
int top;
}sqstack;
int maze[NUM][NUM];//定义迷宫
/*定义栈操作*/
status initstack(sqstack *S){
S->top=-1;
}
status stacklength(sqstack *S){
return S->top+1;
}
status push(sqstack *S,pos p){
S->top++;
S->p[S->top]=p;
}
status pop(sqstack *S){
S->top--;
}
status gettop(sqstack *S,pos *p){
*p=S->p[S->top];
}
status emptystack(sqstack *S){
if(S->top==-1)
return TRUE;
else
return FALSE;
}
/*其他操作*/
/*********************************/
/*设定位置*/
status setpos(pos *p,elemtype x,elemtype y){
p->x=x;
p->y=y;
}
/*设定下一位置next*/
status setnext(pos *p,elemtype next){
p->next=next;
}
/*判断是否可以到达下一个位置*/
status hasnext(pos *p){
int x=0,y=0;
p->next=0;//p->next用于八个方向的确定
while(p->next<8){
p->next++;
/*这部分代码用来让pos在附近的八个位置移动,以判断是否能到达下一位置*/
switch(p->next){
case 1:
x=p->x+1;
y=p->y+1;
break;
case 2:
x=p->x+1;
y=p->y-1;
break;
case 3:
x=p->x-1;
y=p->y+1;
break;
case 4:
x=p->x-1;
y=p->y-1;
break;
case 5:
x=p->x+1;
y=p->y;
break;
case 6:
x=p->x;
y=p->y+1;
break;
case 7:
x=p->x-1;
y=p->y;
break;
case 8:
x=p->x;
y=p->y-1;
break;
}
/*判断移动之后的位置能否到达*/
if(maze[x][y]==0){
p->x=x;
p->y=y;
p->next=0;
return OK;
}
}
return ERROR;//不能到达,返回ERROR
}
/*标记探索过且能通过的点*/
status markpassedpoint(pos *p){
maze[p->x][p->y]=passed;
}
/*标记无路可走的点*/
status markfailedpoint(pos *p){
maze[p->x][p->y]=failed;
}
/*判断出口*/
status isexit(pos *p){
if(p->x==N&&p->y==N)
return TRUE;
return FALSE;
}
/*生成迷宫*/
status makemaze(void){
int i=0,j=0;
srand(time(0));
for(i=0;i<NUM;i++){
for(j=0;j<NUM;j++){
if(i==0||i==NUM-1||j==0||j==NUM-1)//迷宫四周的墙
maze[i][j]=1;
else
maze[i][j]=rand()%2;
}
}
maze[1][1]=maze[NUM-2][NUM-2]=0;//定义出入口
}
/*打印迷宫*/
status printmaze(void){
int i=0,j=0;
for(i=0;i<NUM;i++){
for(j=0;j<NUM;j++){
printf("%d ",maze[i][j]);
}
printf("\n");
}
printf("\n");
}
/*打印路径*/
status printway(sqstack *S){
int i=0;
printf("The avalible way is:\n");
for(i=0;i<S->top;i++)
printf("<%d,%d>->",S->p[i].x,S->p[i].y);
printf("<%d,%d>",S->p[i].x,S->p[i].y);//分开写的目的是让最后一项不出现->
}
/*搜索路径*/
status searchway(){
sqstack S;
pos p;
initstack(&S);
setpos(&p,1,1);//设置初始位置为(1,1)
setnext(&p,0);//设初始位置下一位置可到达
push(&S,p);
markpassedpoint(&p);
/*栈不空是取最上方点进行判断,判断是否为出口*/
while(!emptystack(&S)){
gettop(&S,&p);
if(isexit(&p)){
printway(&S);
return OK;
}
if(hasnext(&p)){
push(&S,p);
markpassedpoint(&p);
}
else{
pop(&S);
markfailedpoint(&p);
}
}
return ERROR;//最终回到了出发点,返回ERROR表示无解
}
status main(void){
sqstack S;
pos p;
initstack(&S);
makemaze();
printf("The Maze is:\n");
printmaze();
if(!searchway()){
printf("\nNo Avalible Ways\n");
}
}
2016-04-14更新:
今天在测试自己写的迷宫的过程中,觉得每次用随机数生成的迷宫常常无解,此时就必须要亲自动手才能让程序重新生成迷宫然后重新寻找路径,十分麻烦。于是我对主程序进行了修改,让其只有在生成一个有解的迷宫后再输出答案(我真机智……)代码如下:
int main(void){
stack S;
pos p;
makemaze();
printf("The Maze is:\n");
printmaze();
if(!searchway()){/*如果没找到路*/
while(!searchway()){
makemaze();/*重新生成迷宫*/
printmaze();
}
}
}