灵感来自于回溯思想,需要定义全局变量path、pathTop用于收集每一步路径。
回退时只需要让pathTop减小,并且将退出前访问的点设回未访问。
每一步都有注释哦,方便理解,花个十分钟看完就会了~
(文末有回溯算法模板)
本文旨在帮助小白理解本题,代码存在冗余部分。改进方法可以去看看我的另一个博客坐标变换哦。
题解:
#include <stdio.h>
#include <string.h>
// 全局变量:用于存储路径的数组和当前路径的长度
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 ;
}
如果文章帮助到你,不要吝啬手里的点赞哦,谢谢~