回溯法解决迷宫问题

今天在又一次看到了回溯法解决关于迷宫的问题,于是在这里分享给大家。

回溯法:对一个包括有很多个结点,每个结点有若干个搜索分支的问题,把原问题分解为若干个子问题求解的算法;当搜索到某个结点发现无法再继续搜索下去时,就让搜索过程回溯(回退)到该节点的前一个结点,继续搜索该节点外的其他尚未搜索的分支;如果发现该结点无法再搜索下去,就让搜索过程回溯到这个结点的前一结点继续这样的搜索过程;这样的搜索过程一直进行到搜索到问题的解或者搜索完了全部可搜索分支没有解存在为止。
迷宫问题用这种方法简直很完美,当我们寻找通路时,当前方无法通过返回到上一层继续搜寻其他没有搜寻的通路,就这样一层一层的找通路,最终找到出口,还有一种情况就是迷宫本来就没有通路,只能是返回到起点。当然还涉及到多条通路时我们如何找到最短通路。
回溯过程如下图所示:
回溯法解决迷宫问题_第1张图片
0表示墙壁,1表示通路,函数参数传入迷宫起点,每次向前一步则把前一步设置为2,防止再次试探该位置。
本题我用迭代法和递归法分别实现了找出迷宫多条通路问题
迭代法代码:

void SearchMazePath(Pos entry) //求取通路 回溯法(迭代)
{
    Stack *s;
    Pos next = entry;
    PushStack(&s,next);
    do
    {
        Maze[next._x][next._y] = 2;
        next = TopStack(s);
        next._x += 1; //if (CheckCoord(next)) 
        {
            PushStack(&s,next);
            continue;
        }

        next = TopStack(s);
        next._x -= 1;//if (CheckCoord(next))
        {
            PushStack(&s,next);
            continue;
        }

        next = TopStack(s);
        next._y += 1;//if (CheckCoord(next))
        {
            PushStack(&s,next);
            continue;
        }

        next = TopStack(s);
        next._y -= 1;//if (CheckCoord(next))
        {
            PushStack(&s,next);
            continue;
        }

        PopStack(&s);  //改层没有通路,则pop掉栈顶,返回到上一层继续试探其他方向
        next = TopStack(s);
    }while (EmptyStack(s) && next._x != entry._x);
}

递归法实现代码:

void SearchMazePathR(Pos entry) //求取通路(递归)
{
    Pos next = entry;
    Maze[next._x][next._y] = 2;

    next = entry;
    next._x -=1;
    if (CheckCoord(next))
        SearchMazePathR(next);

    next = entry;
    next._x +=1;
    if (CheckCoord(next))
        SearchMazePathR(next);

    next = entry;
    next._y -=1;
    if (CheckCoord(next))
        SearchMazePathR(next);

    next = entry;
    next._y +=1;
    if (CheckCoord(next))
        SearchMazePathR(next);
}

条件判断补充代码:

int CheckCoord(Pos pos)
{
    if (pos._x >= 0 && pos._xpos._y >=0 && pos._ypos._x][pos._y] == 1)
    {
        return 1;
    }
    else
        return 0;
}

运行结果:
回溯法解决迷宫问题_第2张图片

寻找最短通路:
此时思路还是利用回溯,一步一步试探通路,但是我们需要修改标记方法。当我们向下一个位置试探时发现该位置可通就把该位置标记为比前一个位置大一的数,当下一个位置是1或者比原位置大的数则确定为通路。当下一个位置是0或者比原位置小的数则确定通。这样当我们遍历完所有通路即可得到最短通路。
先看看试探通路的结果:
回溯法解决迷宫问题_第3张图片
明显可以看出遍历了四条路,最短通路为10步。
代码如下:

void SearchShortPathR(Pos entry,Pos cur) //寻找最短路径
{
    Pos next = entry;
    Pos prev = cur;
    Maze[next._x][next._y] = Maze[prev._x][prev._y] + 1;
    if (next._y == COL-1)
        printf("Exit:(%d ,%d)\n",next._x,next._y);  //打印出口

    next = entry;
    next._x += 1;
    if (CheckCoordS(next,entry))
        SearchShortPathR(next,entry);

    next = entry;
    next._x -= 1;
    if (CheckCoordS(next,entry))
        SearchShortPathR(next,entry);

    next = entry;
    next._y += 1;
    if (CheckCoordS(next,entry))
        SearchShortPathR(next,entry);

    next = entry;
    next._y -= 1;
    if (CheckCoordS(next,entry))
        SearchShortPathR(next,entry);
}

总结回溯法解题通常包含以下三个步骤:

1.针对所给问题,定义问题的解空间;
2.确定易于搜索的解空间结构;
3.以深度优先方式搜索解空间,并在搜索过程中用必要的条件避免无效搜索。

你可能感兴趣的