迷宮問題是一個經典的問題,當迷宮規模較大時,手工求解是十分困難的,所以用善於進行重複繁瑣計算的計算機來求解便十分合適。基本思想和解決“八皇后問題” 的思想一致,都是利用回溯法。從入口開始,探索每一個迷宮中沒有被牆擋住的位置,如果該位置可以移動到下一個位置,則標記該位置已被探索過併入棧;如果不能移動到下一位置,則標記爲探索失敗並回退到上一個位置,如果最終退回了出發點,則說明迷宮無解。下面附上代碼:
#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();
}
}
}