棧的思想用於求解迷宮問題

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

#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();
        }
    } 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章