华为机试 HJ43 迷宫问题 C语言解决(小白版本,便于理解)

灵感来自于回溯思想,需要定义全局变量path、pathTop用于收集每一步路径。

回退时只需要让pathTop减小,并且将退出前访问的点设回未访问。

每一步都有注释哦,方便理解,花个十分钟看完就会了~

(文末有回溯算法模板)

本文旨在帮助小白理解本题,代码存在冗余部分。改进方法可以去看看我的另一个博客坐标变换哦。

题解:

#include 
#include 

// 全局变量:用于存储路径的数组和当前路径的长度
int pathTop = 0;
char path[100][10]; // 存储路径点的数组,每个点最多占用 10 个字符(包括括号和逗号)

// 查找路径的递归函数
void FindARoad(int posx, int posy, int row, int col, int** maze, int** used) {
    // 标记当前位置为已访问
    used[posx][posy] = 1;

    // 如果当前位置是终点,打印路径
    if (posx == row - 1 && posy == col - 1) {
        // 打印路径的起点
        printf("%s\n", path[0]);
        // 打印路径的中间部分
        for (int i = 1; i < pathTop - 1; i += 2) {
            printf("%s\n", path[i]);
        }
        // 打印路径的终点
        printf("%s\n", path[pathTop - 1]);
        return;
    }

    // 尝试向下移动
    if (posx + 1 < row && maze[posx + 1][posy] == 0 && used[posx + 1][posy] == 0) {
        used[posx + 1][posy] = 1;
        // 保存当前路径点
        sprintf(path[pathTop], "(%d,%d)\0", posx, posy);
        pathTop++;
        // 保存移动到的新路径点
        sprintf(path[pathTop], "(%d,%d)\0", posx + 1, posy);
        pathTop++;
        // 递归调用
        FindARoad(posx + 1, posy, row, col, maze, used);
        // 回溯:撤销访问标记和路径
        used[posx + 1][posy] = 0;
        pathTop -= 2;
    }

    // 尝试向右移动
    if (posy + 1 < col && maze[posx][posy + 1] == 0 && used[posx][posy + 1] == 0) {
        used[posx][posy + 1] = 1;
        // 保存当前路径点
        sprintf(path[pathTop], "(%d,%d)\0", posx, posy);
        pathTop++;
        // 保存移动到的新路径点
        sprintf(path[pathTop], "(%d,%d)\0", posx, posy + 1);
        pathTop++;
        // 递归调用
        FindARoad(posx, posy + 1, row, col, maze, used);
        // 回溯:撤销访问标记和路径
        used[posx][posy + 1] = 0;
        pathTop -= 2;
    }

    // 尝试向左移动
    if (posy - 1 >= 0 && maze[posx][posy - 1] == 0 && used[posx][posy - 1] == 0) {
        used[posx][posy - 1] = 1;
        // 保存当前路径点
        sprintf(path[pathTop], "(%d,%d)\0", posx, posy);
        pathTop++;
        // 保存移动到的新路径点
        sprintf(path[pathTop], "(%d,%d)\0", posx, posy - 1);
        pathTop++;
        // 递归调用
        FindARoad(posx, posy - 1, row, col, maze, used);
        // 回溯:撤销访问标记和路径
        used[posx][posy - 1] = 0;
        pathTop -= 2;
    }

    // 尝试向上移动
    if (posx - 1 >= 0 && maze[posx - 1][posy] == 0 && used[posx - 1][posy] == 0) {
        used[posx - 1][posy] = 1;
        // 保存当前路径点
        sprintf(path[pathTop], "(%d,%d)\0", posx, posy);
        pathTop++;
        // 保存移动到的新路径点
        sprintf(path[pathTop], "(%d,%d)\0", posx - 1, posy);
        pathTop++;
        // 递归调用
        FindARoad(posx - 1, posy, row, col, maze, used);
        // 回溯:撤销访问标记和路径
        used[posx - 1][posy] = 0;
        pathTop -= 2;
    }

    // 如果没有到达终点并且不能再移动,则返回
    return;
}

int main() {
    int n, m;
    // 读取迷宫的行数和列数
    scanf("%d %d", &n, &m);

    // 定义迷宫和访问标记数组
    int maze[n][m];
    int visited[n][m];
    memset(visited, 0, sizeof(int) * n * m); // 初始化访问标记数组为 0

    // 读取迷宫的数据
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            scanf("%d", &maze[i][j]);
        }
    }

    // 创建指向迷宫和访问标记数组的指针
    int* ptr[n];
    int* ptr2[n];
    for (int i = 0; i < n; i++) {
        ptr[i] = maze[i];
        ptr2[i] = visited[i];
    }

    // 从起点 (0, 0) 开始寻找路径
    FindARoad(0, 0, n, m, ptr, ptr2);

    return 0;
}

​

回溯算法模板:

可以参考 leetcode(77.组合)

int** res;    //收集所有结果
int* path;   //收集单个结果
int resTop,pathTop;  //指针
void backtrack(){
    if(递归退出条件){
        ...
        return ;
    }
    for(收集该层结果){
        path[pathTop++]=...;
        backtrack();         //递归
        pathTop--;           //回退
    }
    return ;
}

如果文章帮助到你,不要吝啬手里的点赞哦,谢谢~

你可能感兴趣的:(C,华为,c语言,算法)