迷宫求解

6 篇文章 0 订阅
3 篇文章 0 订阅

前言

最近复习一下数据结构,发现一个有趣的迷宫求解问题,当时就没去做,现在来玩玩这个问题。

迷宫问题的简单描述:给定一个迷宫,给定一个起点和终点,找到从起点到终点的一条可行路径。《数据结构(C语言版)》书中的图如下:


解决思路:

1.把上面的迷宫转换为一个二维矩阵,用0表示空白,1表示障碍。

2.从起点开始,用逐步探测的方法寻找路径

       从当前的位置开始探测,按顺时针探测四个方向,

           如果该方向不可行,则标记之。循环探测下一个方向,直到探测到一个可行的方向,否则进行回退操作,把该位置标记为障碍,即此路不通。

           找到可行的方向,把当前位置做个标记,留下脚印,防止在以后的探测中又回到原地,进入死循环。接着挪到这个方向的下一步。

           循环该算法,直到找到终点。


    上面的算法中,涉及到回退的操作,可以用栈来帮助解决。下面的程序实现中写了个简单的Stack实现,支持PUSH和POP操作。

    这里比较困难的也许就是如何定义位置的信息结构了,从上面的分析,位置position有以下一些基本信息:1.位置的坐标(i,j);2.处于这个位置时,前进的方向;3.各个方向的可行状态,例如坐标(1,1)北、东、南、西的方向状态为(1,0,0,1),1表示不可行,1表示可行。这样就可以定义出位置的信息结构体了:

typedef struct{
    int i;
    int j;
    int directions[4];//north,east,south,west,0 means can go throuth,1 means can not go through
    int cur_dir;      //current direction
}pos;
    这样,每当挪动一步,就把该位置信息入栈。当路径不通是可以进行出栈,进行回退探测。

    挪动时有个细节,例如从position1往挪一步到position2,那么position2的方向应该标记为不可行,为什么呢?很简单,要是可以往北的话,那就相当于回退一步了。

    回退操作时也有个细节,例如从position3往东挪一步到position4,在以后的探测中发现position4继续走下去的路是走不通的,那么需要进行回退,退到position3,此时,position3的往东方向应该标记为不可行,然后再探测其它方向。

   我们需要的几个主要的函数:

   1.给定一个坐标,返回该坐标的可行状态,可行还是不可行,还是到终点了    pos_status

    2.在一个位置上,找到下一个可行的方向。                                                           pos_get_dir

    3.在一个位置上,往可行的方向挪动下一步,没找到就进行回退探测。           pos_go

好了,预览下效果再看源代码,其中空白表示可行区域,1表示障碍,2表示终点。找到路径后用箭头把整个路径的前进方向整出来(很帅吧):


源码实现

#include <stdio.h>
#include <stdlib.h>

#define STACK_SIZE  1000
#define STACK_INCREMENT  100

#define STACK_PUSH(stack_p,element) do{\
    if( (stack_p)->count >= (stack_p)->size){\
        (stack_p)->base = (stack_element *)realloc( (stack_p)->base,( (stack_p)->size + STACK_INCREMENT ) * sizeof(stack_element) );\
    }\
    *(stack_p)->top = (stack_element)(element);\
    (stack_p)->top++;\
    (stack_p)->count++;\
  }while(0);

#define STACK_POP(stack_p,element_p) do{\
    if( (stack_p)->top  == (stack_p)->base){\
        element_p = NULL;\
    }else{\
        (stack_p)->top--;\
        *element_p = *(stack_p)->top;\
    }\
  }while(0);

/**position struct*/
typedef struct{
    int i;
    int j;
    int directions[4];//north,east,south,west,0 means can go throuth,1 means can not go through
    int cur_dir;      //current direction
}pos;

typedef pos stack_element;
typedef struct{
    stack_element * base;
    stack_element * top;
    int size;
    int count;
}stack; 
/**Initial the stack */
int stack_init(stack *s){
    s->base = (stack_element *)malloc(STACK_SIZE * sizeof(stack_element));
    if(!s->base){
        return 1;
    }
    s->top = s->base;
    s->size = STACK_SIZE;
    s->count = 0;
    return 0;
}

/** Get the status of maze position */
int pos_status(pos *p,int dir,int maze[][10]){
    int status;
    switch(dir){
        case 0:
            status = maze[ p->i -1 ][ p->j ];
            break;
        case 1:
            status = maze[ p->i ][ p->j + 1 ];
            break;
        case 2:
            status = maze[ p->i +1 ][ p->j ];
            break;
        case 3:
            status = maze[ p->i ][ p->j - 1 ];
            break;
    }
    return status;

}
/** Get the next available direction of current position ,return -1 if not available */
int pos_get_dir(pos *p,int maze[][10]){
    int status,tmp_dir;
    status = pos_status(p,p->cur_dir,maze);
    if(status != 1){
        return p->cur_dir;
    }
    p->directions[p->cur_dir] = 1;
    tmp_dir = p->cur_dir;
    do{
        tmp_dir = (tmp_dir+1)%4;
        if(p->directions[tmp_dir] == 1) continue;

        status = pos_status(p,tmp_dir,maze);
        if(status == 1){
            p->directions[tmp_dir] = 1;
        }else{
            p->cur_dir = tmp_dir;
            return p->cur_dir;
        }
    }while(p->cur_dir != tmp_dir);

    return -1;//no directions available
}
/** Go to the next available position and return 0, return -1 if break down */
int pos_go(pos *p,int maze[][10],stack *sp){
/*    printf("%d,%d\n",p->i,p->j);*/
    int dir,i;
    dir = pos_get_dir(p,maze);
    if(dir != -1){
        STACK_PUSH(sp,*p);
        maze[p->i][p->j] = 1;//mark and leave foot print,avoid recursive going back
        p->directions[3-dir] = 1;//do not go back
        switch(dir){
            case 0:
                p->i--; break;
            case 1:
                p->j++; break;
            case 2:
                p->i++; break;
            case 3:
                p->j--; break;
        }
        for(i=0;i<4;i++){//reset the directions except the current going direction
            if(i != dir){
                p->directions[i] = 0;
            }
        }
    }else{
        maze[p->i][p->j] = 1;//can no go through
        STACK_POP(sp,p);
        if(NULL == p){
            return -1;
        }else{
            p->directions[p->cur_dir] = 1;
        }
    }
    return 0;
}

int main(){
    stack s;
    stack_init(&s);

    int maze[10][10] = {
        {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,2,1},
        {1,1,1,1,1,1,1,1,1,1},
    };
    /**printf the original maze*/
    int i,j;
    for(i=0;i<10;i++){
        for(j=0;j<10;j++){
            if(maze[i][j] == 0){
                printf(" ");
            }else{
                printf("%d",maze[i][j]);
            }
        }
        printf("\n");
    }

    pos goner = {1,1,{0,0,0,0},0};
    while(1){
        if(maze[goner.i][goner.j] == 2){
            STACK_PUSH(&s,goner);
            break;
        }
        if(-1 == pos_go(&goner,maze,&s)){
            printf("no way!\n");
            break;
        }
    }

    /** printf path */
    char * directions[4] = {"↑","→","↓","←"};
    pos *gp;
    gp = &goner;
    while(1){
        STACK_POP((&s),gp);
        if(NULL != gp){
            maze[gp->i][gp->j] = gp->cur_dir + 4;
        }else{
            break;
        }
    }
    for(i=0;i<10;i++){
        for(j=0;j<10;j++){
            if(maze[i][j] == 0){
                printf(" ");
            }else if(maze[i][j] == 1){
                printf("1");
            }else{
                printf("%s",directions[ maze[i][j] - 4 ]);
            }
        }
        printf("\n");
    }

    return 0;
}



  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值