C++ 用回溯法求解迷宫问题(递归)

一、定义:

    回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。

    但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就

    退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

    用回溯法求解问题时常使用递归方法进行试探,或使用栈帮助向前试探和回溯。

 

二、思路:

   1.用一个二维数组表示迷宫:

             数组中的值如果是1,则表示该位置是墙壁,不能通行;

             如果等于0,表示该位置是通路;

      用一个标记数组,标记该位置是否被访问过;

   2.迷宫前进的方向:要定义一个结构体存储方向

            可能有8个方向:东,东南,南,西南,西,西北,北,东北

   3.给一个入口和出口的坐标,从入口入手:

      循环入口的8个方向,如果位置通,则递归该位置,一直递归下去,直到到达出口或者所有方向的路不通回溯;

 

三、实现程序:

/*
 测试数据:
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0 0 1 0 0 0 1 1 0 0 0 1 1 1 1 1 1
1 1 0 0 0 1 1 0 1 1 1 0 0 1 1 1 1
1 0 1 1 0 0 0 0 1 1 1 1 0 0 1 1 1
1 1 1 0 1 1 1 1 0 1 1 0 1 1 0 0 1
1 1 1 0 1 0 0 1 0 1 1 1 1 1 1 1 1
1 0 0 1 1 0 1 1 1 0 1 0 0 1 0 1 1
1 0 0 1 1 0 1 1 1 0 1 0 0 1 0 1 1
1 0 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1
1 0 0 1 1 0 1 1 0 1 1 1 1 1 0 1 1
1 1 1 0 0 0 1 1 0 1 1 0 0 0 0 0 1
1 0 0 1 1 1 1 1 0 0 0 1 1 1 1 0 1
1 0 1 0 0 1 1 1 1 1 0 1 1 1 1 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 
 入口:1 0
 出口:12 16
 */
#include 
using namespace std;

const int XLEN = 14, YLEN=17; // 默认迷宫的行数和列数
int m, p; // 出口坐标
int maze[XLEN+2][YLEN+2]; // 迷宫数组
int mark[XLEN+2][YLEN+2]; // 访问标记数组

struct Offsets {
    int a, b; // a和b是x,y方向的偏移
    // char *dir; // dir是方向 ISO C++11是不允许字符指针指向(存储)字符串
};

// 因为我不需要输出方向,所以把方向去掉
Offsets direction[8] = {
    {-1, 0}, // 北:{-1, 0, "N"}
    {-1, 1}, // 东北:{-1, 1, "NE"}
    {0, 1}, // 东:{0, 1, "E"}
    {1, 1}, // 东南:{1, 1, "SE"}
    {1, 0}, // 南:{1, 0, "S"}
    {1, -1}, // 西南:{1, -1, "SW"}
    {0, -1}, // 西:{0, -1, "W"}
    {-1, -1} // 西北:{-1, -1, "NW"}
};

// 解决迷宫问题的递归算法
bool seekPath(int x, int y);

int main(int argc, const char * argv[]) {
    int i, j, x, y;
    
    // 输入迷宫数据和初始化标记数组
    cout << "请输入" << XLEN << "行和" << YLEN << "列的迷宫数据:" << endl;
    for(i = 0; i < XLEN; i++)
        for(j = 0; j < YLEN; j++) {
            cin >> maze[i][j];
            mark[i][j] = 0;
        }
    cout << "请输入入口位置坐标:";
    cin >> x >> y;
    cout << "请输入出口位置坐标:";
    cin >> m >> p;
    mark[x][y] = 1; // 从入口开始
    // 调用求解迷宫的递归算法
    if(seekPath(x, y)) // 成功
        cout << "(" << x << ", " << y << ")" << endl;
    else
        cout << "找不到从入口到出口的路径!" << endl;
    return 0;
}

// 解决魔攻问题的递归算法
bool seekPath(int x, int y) {
    // 从迷宫某一位置[i][j]开始,寻找出口[m][p]的一条路径,如果找到,则函数返回true
    int i, g, h; // g, h记录位置信息
    // char *dir; // dir记录方向
    
    if(x == m && y == p) // m和p是出口坐标
        return true;
    // 循环遍历(x, y)的8个方向
    for(i = 0; i < 8; i++) {
        g = x + direction[i].a;
        h = y + direction[i].b;
        // dir = direction[i].dir;
        
        // 找下一位置寻找通向出口的路径
        if(maze[g][h] == 0 && mark[g][h] == 0) { // 如果通且未被访问过
            mark[g][h] = 1; // 标记为已访问过
            if(seekPath(g, h)) { // 递归试探
                cout << "(" << g << ", " << h << "),"; // 逆向输出路径坐标
                return true;
            }
        }
        // 回溯,换一个方向再试探通向出口的路径
    }
    return false; // 找不到通向出口的路径
}

 测试结果:

C++ 用回溯法求解迷宫问题(递归)_第1张图片

你可能感兴趣的:(数据结构)