经典迷宫问题DFS 深度优先

   


迷宫问题的总体思路是,从迷宫的入口出发,沿着某一个方向向前试探,若能够行得通,则继续往前走,否则原来返回,再换另一个方向继续试探,直到所有可能的通路都被试探过,为了保证在任何一个位置都能够原来返回,需要设置一个堆栈结构来保存从入口到当前位置的路径。
迷宫可以用一个二维数组maze[1..m][1..n]来表示。数组中的元素值为1时表示该点道路阻塞,为0时表示该点可以进入,这里假定迷宫的入口处元素为maze[1][1], 出口处元素为maze[m][n],那么在maze[1][1]和maze[m][n]处元素值必为0,为了避免走回已经进入过的点,凡是进入过的点应该做一个标记,这里将其赋予一个非0非1的值,假定为2.

迷宫可以用一个二维数组maze[1..m][1..n]来表示。数组中的元素值为1时表示该点道路阻塞,为0时表示该点可以进入,这里假定迷宫的入口处元素为maze[1][1], 出口处元素为maze[m][n],那么在maze[1][1]和maze[m][n]处元素值必为0,为了避免走回已经进入过的点,凡是进入过的点应该做一个标记,这里将其赋予一个非0非1的值,假定为2.

在任意时刻,在迷宫中的位置可以用所在点的行坐标和列坐标表示,这样在迷宫中的某一点位置(i, j)时,其可能运动的方向有8个方向,它的位置可从当前位置的坐标推算,如下:

      

位置计算规则

(i-1, j-1)(i-1, j)(i-1, j+1)
(j, j-1)(i, j)(i, j+1)
(i +1, j -1)(i+1, j)(i+1, j+1)

但是按照这种规则,不是每个位置都有8个方向可以选择,比如在迷宫的4个角和边界上,为了避免讨论边界问题,可以在整个迷宫外面套上一圈其值均为1的元素,因此,作为表示迷宫的二维数组实际上是maze[0..m+1][0..n+1]. 

为了简化运算,将当前位置(i, j)及其相邻8个位置的坐标关系建立一个数组move[0..7][0..1], 假定每次试探的方向都是从正北方向开始,则数组可表示为:

  

move[ 8 ][ 2 ] = {  
 { -1, 0 },  
 { -1, 1 },   
 { 0, 1 },   
 { 1, 1 },   
 { 1, 0 },  
 { 1, -1 },  
 { 0, -1 },   
 { -1, -1 } } 

具体算法描述如下函数int mazepath( int maze[][MaxN], int m, int n ):

    

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

#define MaxN 100
#define MaxMN 10000

 /* m, n是迷宫的维数 */
int mazepath( int maze[][MaxN], int m, int n ){
   /* stack数组用于记录已走过的路径的点(i,j)及选择的方向 */
    int stack[ MaxMN ][ 3 ];
    /* 移动下一步的方向 */
    int move[ 8 ][ 2 ] = { { -1, 0 },
    { -1, 1 }, { 0, 1 }, { 1, 1 }, { 1, 0 },
    { 1, -1 }, { 0, -1 }, { -1, -1 } };
     /* i,j用于记录当前位置的(i,j),(g,h)用于记录下一步的位置 */
    int p, i, j, k, g, h, top = 0;
    /* 起始位置maze[1][1]置一个非0非1的整数 */
    maze[ 1 ][ 1 ] = 2;
    /* stack数组记录第一个位置的坐标 */
    stack[ 0 ][ 0 ] = 1;
    stack[ 0 ][ 1 ] = 1;
    stack[ 0 ][ 2 ] = 1;
    /* 如果当前位置没有下一步可走,则退栈返回上一个位置的下一个方向 */
    while( top >= 0 ){
        i = stack[ top ][ 0 ];
        j = stack[ top ][ 1 ];
         /* k为方向数,初始值为2,即方向向东,+1表示移向下一个方向 */
        k = stack[ top-- ][ 2 ] + 1;
        while( k < 8 ){
            /* 计算下一个位置的坐标(g,h) */
            g = i + move[ k ][ 0 ];
            h = j + move[ k ][ 1 ];
                /* 若找到了迷宫的出口 */
            if( g == m && h == n && maze[ g ][ h ] == 0 ){
                printf( "\n找到一条通道!\n" );
                /* 遍历堆栈,打印堆栈信息 */
                for( p = 0; p <= top; p++ )
                    printf( "(%d, %d)\n", stack[ p ][ 0 ], stack[ p ][ 1 ] );
                  /* 打印当前位置(i,j)和出口位置(m,n) */
                printf( "(%d, %d)\n", i, j );
                printf( "(%d, %d)\n", m, n );
                return 1;
            }
            /* 找到通路上的一个位置(g,h) */
            if( maze[ g ][ h ] == 0 ){
                /* 在maze[g][h]置一个非0非1的整数 */
                maze[ g ][ h ] = 2;
              /* 将当前位置信息(i,j)及所选方向数入栈 */
                stack[ ++top ][ 0 ] = i;
                stack[ top ][ 1 ] = j;
                stack[ top ][ 2 ] = k;
                 /* 更新当前位置信息为通路上的下一个位置 */
                i = g;
                j = h;
                k = 0;
            }
            k++;
        }
    }
    printf( "\n迷宫中没有发现通路!\n" );
    return 0;
}

int main(){
    int maze[8][MaxN] = {
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1 },
        { 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1 },
        { 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1 },
        { 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1 },
        { 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1 },
        { 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1 },
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }

    };
    mazepath( maze, 6, 9 );
}

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