栈-迷宫求解

版权声明:转载请注明出处。 https://blog.csdn.net/baidu_38304645/article/details/82940648

求迷宫中从入口到出口的所有路径是一个经典的程序设计问题。由于计算机解迷宫时,通常用的是穷举求解的方法,即从入口出发,顺某一方向向前探索,若能走通,则继续往前走,否则沿原路退回,换一个方向再继续探索,直至所有可能的通路都探索到为止。为了保证在任何位置上都能沿原路退回,用栈来保存从入口到当前位置的路径就是自然的事情了。

运行结果:

算法思路:

令curPos指向入口,curStep为1,重复

while(TRUE)

{

若当前位置通,则将其纳入路径(栈),是出口停,非出口重置curPos为右邻,开始下次循环。若当前位置不同,看上一步,若其四周均已访问过,则将其从路径中删除,如此重复直到找到一个曾经访问之位置。其四个方向至少有一个未曾访问过,此时重置curPos为此未访问邻块,开始下次循环,若栈空仍然未找到则退出。

}

首先是辅助宏的定义:

//墙及通路及前进方向符号定义
#define WALL 0   //代表当前格子是墙
#define PATH 1   //代表是通路且未走过
#define RIGHT -1 //代表是通路且从其向右走
#define DOWN -2  //代表是通路且从其向下走
#define LEFT -3  //代表是通路且从其向左走
#define UP -4    //代表是通路且从其向上走
#define BACK -5  //代表是通路且从其后退一步
#define DESTINATION -6//代表是通路且是目标位置
#define EXIT -7
typedef int MazeType[10][10];//最外初始化成墙
typedef int Status;
typedef int ElemType;//迷宫中数组的元素类型

栈中元素类型定义:

typedef struct
{
    int x,y;
} PosType;
typedef struct
{
    int ord;//通道块在路径上的序号
    PosType  seat;//通道块在迷宫的位置
    int di; //从此通道块到下一通道块的方向
} SElemType;

在迷宫中留下足迹。

void FootPrint(MazeType &maze,PosType curpos,Status s)
{
    //留下足迹
    maze[curpos.x][curpos.y]=s;
}

返回下一个位置.

PosType Nextpos(PosType curpos,Status s)
{
    //返回下一个位置
    switch(s)
    {
    case RIGHT:
        curpos.y++;
        break;
    case DOWN:
        curpos.x++;
        break;
    case LEFT:
        curpos.y--;
        break;
    case UP:
        curpos.x--;
        break;
    }
    return curpos;
}

生成迷宫,0表示通PATH,1表示不通WALL.

//迷宫求解的具体算法
Status MakeMaze(MazeType &maze)
{
    //生成迷宫,0表示通PATH,1表示不通WALL
    int x,y;
    srand(time(NULL));
    for(y=0; y<=9; y++)
    {
        maze[0][y]=WALL;
        maze[9][y]=WALL;
    }
    for(x=1; x<=8; x++)
    {
        maze[x][0]=WALL;
        maze[x][9]=WALL;
    }
    for(x=1; x<=8; x++)
        for(y=1; y<=8; y++)
            maze[x][y]=rand()%2;
    return OK;
}

输出迷宫.

void PrintMaze(MazeType maze)
{
    //输出迷宫
    int x,y;
    for(x=0; x<=9; x++)
    {
        for(y=0; y<=9; y++)
        {
            switch(maze[x][y])
            {
            case WALL:
                printf("■");
                break;
            case PATH:
                printf("  ");
                break;
            case RIGHT:
                printf("→");
                break;
            case DOWN:
                printf("↓");
                break;
            case LEFT:
                printf("←");
                break;
            case UP:
                printf("↑");
                break;
            case BACK:
                printf("@ ");
                break;
            case DESTINATION:
                printf("◎");
                break;
            default:
                printf("error");
            }
        }
        printf("\n");
    }
}

输出具体路径.

Status PrintSElem(SElemType e)
{
    //输出坐标
    printf("(%d,%d)\n",e.seat.x,e.seat.y);
    return OK;
}

void StackTraverse(SqStack S,Status (*PrintSElem)(SElemType))
{
    //输出具体路径
    int len=S.top-S.base;
    for(int i=1; i<=len; i++)
    {
        printf("step:%d to ",i);
        PrintSElem(S.base[i-1]);
    }
}

算法实现:

求迷宫中start到end的通路,有通路返回TRUE,没通路返回FALSE,栈S返回路径。

Status PassMaze(MazeType &maze,PosType start,PosType end,SqStack &S)
{
    //求迷宫中start到end的通路,有通路返回TRUE,没通路返回FALSE,栈S返回路径
    PosType curpos=start;//当前位置为开始位置
    int curstep=1;//探索第一步
    SElemType e;
    if(maze[curpos.x][curpos.y]!=PATH)//入口不通则停
        return FALSE;
    while(1) //从当前位置处理,不断找cospos重复,直到栈空或者找到出口
    {
        if(maze[curpos.x][curpos.y]==PATH) //当前位置可通
        {
            e.di=RIGHT;//右邻马上被访问
            e.seat=curpos;
            e.ord=curstep;
            Push(S,e);//加入路径
            if(curpos.x==end.x&&curpos.y==end.y) //到达终点
            {
                FootPrint(maze,curpos,DESTINATION);//留下足迹
                return OK;
            }
            else
            {
                FootPrint(maze,curpos,RIGHT);
                curpos=Nextpos(curpos,RIGHT);//下一位置是当前位置的东临
            }
        }
        else  //当前位置不通
        {
            if(StackEmpty(S))
                return FALSE;
            GetTop(S,e);//取最近到过的位置查看信息
            while(e.di==-4) //四周都访问过
            {
                Pop(S,e);
                curstep--;
                FootPrint(maze,e.seat,BACK);//后退一步 留下不能通过的标记
                GetTop(S,e);
            }
            if(e.di>-4) //栈顶位置有其他方向可以选择
            {
                Pop(S,e);
                e.di--; //换一个方向
                Push(S,e);//修改栈顶位置信息
                FootPrint(maze,e.seat,e.di);
                curpos=Nextpos(e.seat,e.di);//设定当前位置是新方向上的相邻块
            }
        }
    }
    return OK;
}

猜你喜欢

转载自blog.csdn.net/baidu_38304645/article/details/82940648