回溯法解决迷宫问题(方法1---递归)

一、解决思路

1.创建迷宫,用0表示无障碍位置,1表示墙壁,比如迷宫m*p表示m行、p列,用二维数组Maze[m][p].但为了边缘处能够方便处理,在迷宫外层加一层几乎都为1的墙壁,除了进口和入口处设置为0,即辅助迷宫为Maze[m+2][p+2].

2.当进入迷宫时,如何选择前进的方向,如何判断哪个方向是0或者1呢?

 这就要利用一个结构体来表示下一步的位置坐标,(g,h)以及前进方向dir【】;

 

struct offsets{                       //位置在直角坐标下的偏移
    int a,b;                          //a,b是x,y方向的偏移
    char dir[3];                        //dir是方向
};
offsets Move[8]={{0,-1,"W"},{-1,-1,"NW"},{-1,0,"N"},{-1,1,"NE"},{0,1,"E"},{1,1,"SE"},{1,0,"S"},{1,-1,"SW"}};    

3.回溯法核心思想就是每次试探一个点,沿着这个点试探下去,如果遇到死胡同,则退一步,再换方向试探,在这个过程中,每次试探时,应将该点标记,使得如果试探失败,下次试探时,不再试探这个位置。

 

利用标记数组mark[m+2][n+2],初始化为0,每试探一个位置,标记为1,所以每次试探时不仅要判断Maze坐标值是否为0,还要判断mark标记值是否为0,如果都为0,才可以试探。

4.注意试探的时候还要判断g,h是否都是非负值,防止访问数组外的值,可能进入死循环。

 

 

#include <iostream>
#include <cstring>
const int m=5,p=6;
#include "Maze.h"
using namespace std;
int Maze[m+2][p+2];
int mark[m+2][p+2];                    //全局变量,自动赋值为0
struct offsets{                       //位置在直角坐标下的偏移
    int a,b;                          //a,b是x,y方向的偏移
    char dir[3];                        //dir是方向
};
offsets Move[8]={{0,-1,"W"},{-1,-1,"NW"},{-1,0,"N"},{-1,1,"NE"},{0,1,"E"},{1,1,"SE"},{1,0,"S"},{1,-1,"SW"}};                    //各个方向的偏移表
int SeekPath(int x,int y)
//从迷宫某一位置[i][j]开始,寻找通向出口[m][p]的一条路径,如果找到,函数返回1
//否则函数返回0,试探点的出发点为[1][1]
{
    int i,g,h;                      //g,h记录位置信息
    char d[3];                        //d记录方向
    if(x==m&&y==p) return 1;        //到达出口
    for(i=0;i<8;i++)                //依次按每一个方向寻找通向出口的路径
    {
        g=x+Move[i].a;                                            //找下一个位置g,h,d;
        h=y+Move[i].b;
        strcpy(d,Move[i].dir);
        if(Maze[g][h]==0&&mark[g][h]==0&&g>=0&&h>=0)              //试探坐标值为0位置和标记值为0的值,同时g、h必须大于等于0,否则死循环
        {
            mark[g][h]=1;                                        //将试探过的点标记值记作1,下次不能再试探
            if(SeekPath(g,h))                                     //试探g、h点
            {
                cout<<"("<<g<<","<<h<<"),"<<"Direction "<<d<<endl;
                return 1;                                        //试探成功,逆向输出路径坐标,一旦某个试探成功,则返回,不进行下面的换方向试探
            }
        }
                                                                  //回溯,换一个方向在试探通向出口的路径
    }
    if(x==1&&y==1)  cout<<"无法出去"<<endl;
    return 0;

}

/*
1 1 1 1 1 1 1 1
0 0 0 1 1 1 1 1
1 0 1 0 1 1 0 1
0 1 1 0 1 1 0 1
1 1 1 1 0 0 1 1
1 1 1 0 0 1 0 0
1 1 1 1 1 1 1 1
*/

int main()
{
    int i,j;


    for(i=0;i<m+2;i++)
        for(j=0;j<p+2;j++) cin>>Maze[i][j];
    mark[1][1]=1;                                                    //将迷宫进口标记为1,防止下一步试探进口
    if(SeekPath(1,1))
        cout<<"(1,1),Direction E"<<endl;

    //cout<<Maze[m][p]<<endl;

    return 0;
}

 

 

 

 

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