迷宫问题,另辟蹊径,不用递归不用栈

迷宫的求解问题,通常的做法是采用穷举法, 数据结构使用到栈,这也是目前基本所有的数据结构与算法类书籍给出的一般解法。

本文介绍另外一种算法求解, 不需要用到栈。

算法思想:
关于迷宫, 不失一般性, 沿着一个方向走,碰到墙壁可以回头。
沿着一个方向一直走下去,如顺时针,如果迷宫有解,那么必定会走到出口,如果最后又返回到入口的方向,说明迷宫无解。
此算法不需要用到额外的数据结构,这是它的优点,只需要注意到下一方向的计算,以及探寻位置不通后的返回位置。缺点也很显明,那就是同一位置可能会走过两次。
算法的时间复杂度O(m*n),m、n表示迷宫的长宽, 空间复杂度O(1)。

源码如下:

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

/**@brief find maze path * 10 * 10 的迷宫, 字符为‘#’,表示不能通过,‘0’表示可以通过,走过的路径用‘1’标记 * 入口a[0][0],出口a[9][9],假定入口是通的 * @return 1, 0 */
int maze_path(char maze[10][10])
{
    int dir = 1;  //前进方向指示,1,2,3,4依次表示东、南、西、北方向,前进方向一走沿着东南西北的顺序方向;初始方向为东

    int tmp_i, tmp_j, i, j; /* i j 用来表示当前的位置,tmp_i, tmp_j用来探寻下一位置,如果不通不会走过去*/

    i = 0;
    j = 0;
    tmp_i = 0;
    tmp_j = 0;
    maze[0][0] = '1';   //标记入口是通的

    do
    {
        /* 根据探寻前进方向,求出探寻位置点 */
        switch (dir)
        {
            case 1:
                tmp_j++;
                break;

            case 2:
                tmp_i++;
                break;

            case 3:
                tmp_j--;
                break;

            case 4:
                tmp_i--;
                break;
        }

        if ((tmp_i>=0)&&(tmp_i<=9)&&(tmp_j>=0)&&(tmp_j<=9)&&('#' != maze[tmp_i][tmp_j])) //探寻位置不是墙
        {
            /* 位置通过,i j 走到探寻的tmp_i tmp_j位置,且标记为字母'1' */
            i = tmp_i;
            j = tmp_j;
            maze[i][j] = '1';

            if (9==i && 9==j)
            {//走到了出口,返回
                return 1; 
            }

            /* 方向指示,如果是由上一个位置过来,则方向对应: 东西南北-> 西东北南 */
            if (dir >= 3)
            {
                dir -= 2;
            }
            else
            {
                dir += 2;
            }
        }
        else
        {//探寻位置是墙
            if (0==i && 0==j && 4==dir)  //又回到了入口,且探寻到北方向,说明已经探寻完毕,没有路径
            {
                return 0;
            }

            /* 探寻的位置回退,准备探寻下一方向 */
            tmp_i = i;
            tmp_j = j;
        }

        /* 方向指示到下一方向 */
        if (4 == dir) 
        {
            dir = 1;  //当前是北,下一方向指向东
        }
        else
        {
            dir++; 
        }   

    }while(1);
}

/* demo */
int main()
{
    char maze[10][10];
    int i = 0;
    int j = 0;

    srand(time(NULL)); //random seed

    do
    {
        /* 1 随机生成迷宫 */
        memset(maze, '0', sizeof(maze));
        for (i=0; i<40; i++)
        {
            *((char*)((char*)maze+rand()%98+1)) = '#';   //a[0][1] 到 a[9][8],随机置'#'迷宫墙,跳过入口a[0][0]出口a[9][9]
        }
        printf("maze:\n");
        for (i=0; i<10; i++)
        {
            for (j=0; j<10; j++)
            {
                printf("%c ", maze[i][j]);
            }
            printf("\n");
        }
        printf("\n");

        /* 2 找迷宫路径 */
        if (maze_path(maze) == 1)
        {
            printf("find path:\n");
            for (i=0; i<10; i++)
            {
                for (j=0; j<10; j++)
                {
                    printf("%c ", maze[i][j]);
                }
                printf("\n");
            }
            printf("\n");
        }
        else
        {
            printf("no path:\n");
            for (i=0; i<10; i++)
            {
                for (j=0; j<10; j++)
                {
                    printf("%c ", maze[i][j]);
                }
                printf("\n");
            }
            printf("\n");
        }

        printf("Enter q to leave, the other key to continue...\n ");
    }while (getchar() != 'q');

    return 0;
}

测试结果:
《迷宫问题,另辟蹊径,不用递归不用栈》

后记:
生活中越来越多的主题乐园都有迷宫,供游客游玩, 如果在限定时间内走出迷宫,有些地方还会提供奖励。其实实际走迷宫, 不可能按照计算机递归的方式去穷举,你不可能记住之前走过的那么多步骤。假如按照本文的算法思想,走出迷宫是一件很轻而易举的事:
一走沿着一个方向走, 比如遇到叉路就向右拐,遇到死胡同就调头。这么说可能还是有人不明白,但简单些, 从入口进去,右手扶着墙壁,然后一直往前走的过程中,保持右手始终可以接触墙壁。
只要你走路速度够快,能快速也走出迷宫,so easy。

    原文作者:迷宫问题
    原文地址: https://blog.csdn.net/c20130911/article/details/75098208
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞