走迷宫算法(C回溯递归)

引言

迷宫算法在很多场景都非常实用,比如游戏中的机器人等。而且高级的迷宫算法与回溯、递归也是息息相关的。而且回溯的用途更为广阔,如下棋游戏等。

请用代码走出下面的迷宫,并且将所有可能都列出。(R为当前开始位置)

  0 1 2 3 4 5 6 7 8 9
0 # # # # # # # # # #
1 #       #   # # # #
2 #   #   #   # # # #
3 #   #           # #
4 #   #   # #   # # #
5 #   #     #   # # #
6 #   # #   #       #
7 #   # # # # # #   #
8 #                 #
9 # R # # # # # #   #

原理

方法1:走迷宫算法本质是使用的一个栈,初始化栈为开始顶点(9,1,0)【x:9,y:1,d:0】,在从栈顶取出(x,y,d)【x:表示第几行,y:表示第几列,d:表示从哪个方向走】开始向d方向走之前先进行的判断,如果行的通(不为#,不为R,不越界)进行标记,已表明走过,并且将(x,y,d)放入到栈中;如果行不通则进行方向的加1然后在进行判断,一直到d=4则(就是上下左右都行不通)进行弹栈,依次类推。

方法2:我们从方法1中可以看出迷宫算法一直都是对栈顶进行操作,所以咱们可以不可以用递归来实现一下。思想非常的简单,就是每走一步就向四个方向进行验证,行的通就走,行不通就不走。具体看代码(备注很明白);

代码

# include "stdio.h"
# include "windows.h"

# define UP 0 //定义上
# define DOWN 1 //定义下
# define LEFT 2 //定义左
# define RIGHT 3 //定义右

# define MAP_MAX 10 //定义最大地图
int map[MAP_MAX][MAP_MAX] =
{
    {1,1,1,1,1,1,1,1,1,1},
    {1,0,0,0,1,0,1,1,1,1},
    {1,0,1,0,1,0,1,1,1,1},
    {1,0,1,0,0,0,0,0,1,1},
    {1,0,1,0,1,1,0,1,1,1},
    {1,0,1,0,0,1,0,1,1,1},
    {1,0,1,1,0,1,0,0,0,1},
    {1,0,1,1,1,1,1,1,0,1},
    {1,0,0,0,0,0,0,0,0,1},
    {1,2,1,1,1,1,1,1,0,1}//手动在出发点标了个2
};

/*
    打印地图
*/
void print_map()
{
    int i,j;
    char emt[]=" #R";
    //定义显示的数组
    putchar(' ');
    for(j=0; j<MAP_MAX; j++)
    {
        printf(" %d", j);
    }
    putchar('\n');
    for(i=0; i<MAP_MAX; i++)
    {
        printf("%d ", i);
        for(j=0; j<MAP_MAX; j++)
        {
            printf("%c ", emt[map[i][j]]);
        }
        putchar('\n');
    }
}


/*
    单纯的移动,并且进行值的改变
*/
void move(int &x, int &y, int d)
{
    switch(d)
    {
    case UP:
        x--;
        break;
    case DOWN:
        x++;
        break;
    case LEFT:
        y--;
        break;
    case RIGHT:
        y++;
        break;
    }
}
/*
    检查下一步是否可行
    x,y点开始
    d方向
*/
int inspect(int x,int y,int d)
{
    // printf("%d %d %d\n", x,y,d);
    move(x,y,d);

    if(x<0 || y<0|| x>=MAP_MAX || y>=MAP_MAX || map[x][y]!=0)
    {
        return 0;
    }

    return 1;
}

void print_pro(int s[2], int e[2], int n){
    /*打印过程*/
    Sleep(0);
    //system("cls");
    printf("当前:(%d, %d) 终点:(%d, %d) 步数:%d\n", s[0],s[1],e[0],e[1],n);
    print_map();
    /*--------*/
}

/*
    走迷宫(递归回溯所有可能都走)
    s是开始坐标
    e是结束坐标
    n当前第几步
*/
int mazes(int s[2],int e[2],int n)
{
    if(s[0]==e[0] && s[1]==e[1]){
        print_pro(s,e,n);
    }

    int i;
    for(i=0; i<4; i++)//向四个方向同时走
    {
        if(inspect(s[0],s[1],i))//检查i方向是否可以行得通
        {
            int tx = s[0], ty = s[1];//设置临时变量,防止数据混乱
            move(tx,ty,i);//向i方向移动一步
            map[tx][ty] = 2;//标记已走
            int ta[2] = {tx,ty};//传值变量
            mazes(ta,e,n+1);
            map[tx][ty] = 0;//取消标记
        }
    }
}

int main()
{
    int n = 0;//初始步数
    int s[2] = {9,1};//s初始位置
    int e[2] = {9,8};//e终止位置
    mazes(s,e,n);//调用走迷宫
    putchar('\n');
    return 0;
}

结果

当前:(9, 8) 终点:(9, 8) 步数:23
  0 1 2 3 4 5 6 7 8 9
0 # # # # # # # # # #
1 # R R R #   # # # #
2 # R # R #   # # # #
3 # R # R R R R   # #
4 # R #   # # R # # #
5 # R #     # R # # #
6 # R # #   # R R R #
7 # R # # # # # # R #
8 # R             R #
9 # R # # # # # # R #
当前:(9, 8) 终点:(9, 8) 步数:9
  0 1 2 3 4 5 6 7 8 9
0 # # # # # # # # # #
1 #       #   # # # #
2 #   #   #   # # # #
3 #   #           # #
4 #   #   # #   # # #
5 #   #     #   # # #
6 #   # #   #       #
7 #   # # # # # #   #
8 # R R R R R R R R #
9 # R # # # # # # R #

结语

迷宫算法还是很有研究的必要,因为他涉及 栈、递归、回溯、生成树这些知识点。通过迷宫算法可以更深一步理解。如果有什么问题可以评论,如果想要栈的走迷宫代码,可以私信我。

转载于:https://www.jianshu.com/p/3178d0e336c7

猜你喜欢

转载自blog.csdn.net/weixin_34051201/article/details/91297253