迷宫问题

简介: 迷宫问题是指在给定区域内寻找从起点到终点的可行路径。可以使用回溯算法解决,通过不断尝试四个方向(上下左右)移动,若无法前进则回退,直到找到终点或遍历所有可能路径。文中还给出了C语言、Java和Python的实现代码,并展示了运行结果。

迷宫问题指的是:在给定区域内,找到一条甚至所有从某个位置到另一个位置的移动路线。举个简单的例子,如图 1 所示,在白色区域内找到一条(甚至所有)从起点到终点的路线。


图1:迷宫问题


迷宫问题就可以采用回溯算法解决,即从起点开始,采用不断“回溯”的方式逐一试探所有的移动路线,最终找到可以到达终点的路线。

回溯算法解决迷宫问题

以图 1 所示的迷宫为例,回溯算法解决此问题的具体思路是:

  1. 从当前位置开始,分别判断是否可以向 4 个方向(上、下、左、右)移动:
  2. 选择一个方向并移动到下个位置。判断此位置是否为终点,如果是就表示找到了一条移动路线;如果不是,在当前位置继续判断是否可以向 4 个方向移动;
  3. 如果 4 个方向都无法移动,则回退至之前的位置,继续判断其它的方向;
  4. 重复 2、3 步,最终要么成功找到可行的路线,要么回退至起点位置,表明所有的路线都已经判断完毕。


程序中,我们可以用特殊的字符表示迷宫中的不同区域。例如,用 1 表示可以移动的白色区域,用 0 表示不能移动的黑色区域,图 1 的迷宫可以用如下的 0-1 矩阵来表示:

1 0 1 1 1

1 1 1 0 1

1 0 0 1 1

1 0 0 1 0

1 0 0 1 1

如下是用回溯算法解决迷宫问题的伪代码:

输入 maze[ROW][COL]   //输入迷宫地图,0 表示黑色区域,1 表示可行走区域

//(row,col) 表示起点,(outrow,outcol)表示终点

maze_puzzle(maze,row,col,outrow,outcol):

   //回溯过程中,行走的每一区域都设为 Y,表示已经进行了判断

   maze[row][col] <- 'Y'

   //如果行走至终点,表明有从起点到终点的路线

   if row == outrow && col == outcol:

       Print maze  // 输出行走路线

       return

   //判断是否可以向上移动

   if canMove(maze,row-1,col):

       maze_puzzle(maze,row-1,col,outrow,outcol)

   //判断是否可以向左移动

   if canMove(maze,row,col-1):

       maze_puzzle(maze,row,col-1,outrow,outcol)

   //判断是否可以向下移动

   if canmove(maze,row+1,col):

       maze_puzzle(maze,row+1,col,outrow,outcol)

   //判断是否可以向右移动

   if canmove(maze,row,col+1):

       maze_puzzle(maze,row,col+1,outrow,outcol)


结合伪代码,如下为解决迷宫问题的 C 语言程序:

  1. #include <stdio.h>
  2. typedef enum { false, true } bool;
  3. #define ROW 5
  4. #define COL 5
  5. //假设当前迷宫中没有起点到终点的路线
  6. bool find = false;
  7. //回溯算法查找可行路线
  8. void maze_puzzle(char maze[ROW][COL], int row, int col, int outrow, int outcol);
  9. //判断 (row,col) 区域是否可以移动
  10. bool canMove(char maze[ROW][COL], int row, int col);
  11. //输出行走路线
  12. void printmaze(char maze[ROW][COL]);
  13. int main()
  14. {
  15. char maze[ROW][COL] = {
  16. {'1','0','1','1','1'},
  17. {'1','1','1','0','1'},
  18. {'1','0','0','1','1'},
  19. {'1','0','0','1','0'},
  20. {'1','0','0','1','1'} };
  21. maze_puzzle(maze, 0, 0, ROW - 1, COL - 1);
  22. if (find == false) {
  23. printf("未找到可行线路");
  24. }
  25. return 0;
  26. }

  27. //(row,col) 表示起点,(outrow,outcol)表示终点
  28. void maze_puzzle(char maze[ROW][COL], int row, int col, int outrow, int outcol) {
  29.    maze[row][col] = 'Y'; // 将各个走过的区域标记为 Y
  30. //如果行走至终点,表明有从起点到终点的路线
  31. if (row == outrow && col == outcol) {
  32.        find = true;
  33. printf("成功走出迷宫,路线图为:\n");
  34. printmaze(maze);
  35. return;
  36. }
  37. //尝试向上移动
  38. if (canMove(maze, row - 1, col)) {
  39. maze_puzzle(maze, row - 1, col, outrow, outcol);
  40. //如果程序不结束,表明此路不通,恢复该区域的标记
  41.        maze[row - 1][col] = '1';
  42. }
  43. //尝试向左移动
  44. if (canMove(maze, row, col - 1)) {
  45. maze_puzzle(maze, row, col - 1, outrow, outcol);
  46. //如果程序不结束,表明此路不通,恢复该区域的标记
  47.        maze[row][col - 1] = '1';
  48. }
  49. //尝试向下移动
  50. if (canMove(maze, row + 1, col)) {
  51. maze_puzzle(maze, row + 1, col, outrow, outcol);
  52. //如果程序不结束,表明此路不通,恢复该区域的标记
  53.        maze[row + 1][col] = '1';
  54. }
  55. //尝试向右移动
  56. if (canMove(maze, row, col + 1)) {
  57. maze_puzzle(maze, row, col + 1, outrow, outcol);
  58. //如果程序不结束,表明此路不通,恢复该区域的标记
  59.        maze[row][col + 1] = '1';
  60. }
  61. }

  62. //判断 (row,col) 区域是否可以移动
  63. bool canMove(char maze[ROW][COL], int row, int col) {
  64. //如果目标区域位于地图内,不是黑色区域,且尚未行走过,返回 true:反之,返回 false
  65. return row >= 0 && row <= ROW - 1 && col >= 0 && col <= COL - 1 && maze[row][col] != '0' && maze[row][col] != 'Y';
  66. }

  67. //输出可行的路线
  68. void printmaze(char maze[ROW][COL]) {
  69. int i, j;
  70. for (i = 0; i < ROW; i++) {
  71. for (j = 0; j < COL; j++) {
  72. printf("%c ", maze[i][j]);
  73. }
  74. printf("\n");
  75. }
  76. }


如下为解决迷宫问题的 Java 程序:

  1. public class Demo {
  2. static boolean find = false;
  3. static int ROW = 5;
  4. static int COL = 5;
  5. //(row,col) 表示起点,(outrow,outcol)表示终点
  6. public static void maze_puzzle(char [][] maze, int row, int col, int outrow, int outcol) {
  7.        maze[row][col] = 'Y'; // 将各个走过的区域标记为 Y
  8. //如果行走至终点,表明有从起点到终点的路线
  9. if (row == outrow && col == outcol) {
  10.            find = true;
  11.            System.out.println("成功走出迷宫,路线图为:");
  12. printmaze(maze);
  13. return ;
  14. }
  15. //尝试向上移动
  16. if (canMove(maze, row - 1, col)) {
  17. maze_puzzle(maze, row - 1, col, outrow, outcol);
  18. //如果程序不结束,表明此路不通,恢复该区域的标记
  19.            maze[row - 1][col] = '1';
  20. }
  21. //尝试向左移动
  22. if (canMove(maze, row, col - 1)) {
  23. maze_puzzle(maze, row, col - 1, outrow, outcol);
  24. //如果程序不结束,表明此路不通,恢复该区域的标记
  25.            maze[row][col - 1] = '1';
  26. }
  27. //尝试向下移动
  28. if (canMove(maze, row + 1, col)) {
  29. maze_puzzle(maze, row + 1, col, outrow, outcol);
  30. //如果程序不结束,表明此路不通,恢复该区域的标记
  31.            maze[row + 1][col] = '1';
  32. }
  33. //尝试向右移动
  34. if (canMove(maze, row, col + 1)) {
  35. maze_puzzle(maze, row, col + 1, outrow, outcol);
  36. //如果程序不结束,表明此路不通,恢复该区域的标记
  37.            maze[row][col + 1] = '1';
  38. }
  39. }
  40. //判断(row,col)区域是否可以移动
  41. public static boolean canMove(char [][] maze, int row, int col) {
  42. //如果目标区域位于地图内,不是黑色区域,且尚未移动过,返回 true:反之,返回 false
  43. return row >= 0 && row <= ROW - 1 && col >= 0 && col <= COL - 1 && maze[row][col] != '0' && maze[row][col] != 'Y';
  44. }
  45. //输出行走路线
  46. public static void printmaze(char [][] maze) {
  47. for(int i=0;i<ROW;i++) {
  48. for(int j=0;j<COL;j++) {
  49.                System.out.print(maze[i][j]+" ");
  50. }
  51.            System.out.println();
  52. }
  53. }
  54. public static void main(String[] args) {
  55. char [][]maze = new char[][]{
  56. {'1','0','1','1','1'},
  57. {'1','1','1','0','1'},
  58. {'1','0','0','1','1'},
  59. {'1','0','0','1','0'},
  60. {'1','0','0','1','1'} };
  61. maze_puzzle(maze, 0, 0, ROW - 1, COL - 1);
  62. if (find == false) {
  63.            System.out.print("未找到可行线路");
  64. }
  65. }
  66. }


如下为解决迷宫问题的 Python 程序:

  1. #指定地图的行数和列数
  2. ROW = 5
  3. COL = 5
  4. #初始化地图
  5. maze =[['1','0','1','1','1'],
  6. ['1','1','1','0','1'],
  7. ['1','0','0','1','1'],
  8. ['1','0','0','1','0'],
  9. ['1','0','0','1','1']]
  10. #假设当前迷宫中没有起点到终点的路线
  11. find = False
  12. #回溯算法查找可行路线
  13. def maze_puzzle(maze,row,col,outrow,outcol):
  14. global find
  15.    maze[row][col] = 'Y'
  16. if row == outrow and col == outcol:
  17.        find = True
  18. print("成功走出迷宫,路线图为:")
  19. printmaze(maze)
  20. return
  21. if canMove(maze,row-1,col):
  22. maze_puzzle(maze, row - 1, col, outrow, outcol)
  23. #如果程序不结束,表明此路不通,恢复该区域的标记
  24.        maze[row - 1][col] = '1'
  25. if canMove(maze, row, col - 1):
  26. maze_puzzle(maze, row, col - 1, outrow, outcol)
  27. #如果程序不结束,表明此路不通,恢复该区域的标记
  28.        maze[row][col - 1] = '1'
  29. #尝试向下移动
  30. if canMove(maze, row + 1, col):
  31. maze_puzzle(maze, row + 1, col, outrow, outcol)
  32. #如果程序不结束,表明此路不通,恢复该区域的标记
  33.        maze[row + 1][col] = '1'
  34. #尝试向右移动
  35. if canMove(maze, row, col + 1):
  36. maze_puzzle(maze, row, col + 1, outrow, outcol)
  37. #如果程序不结束,表明此路不通,恢复该区域的标记
  38.        maze[row][col + 1] = '1'

  39. #判断(row,col)区域是否可以移动
  40. def canMove(maze,row,col):
  41. return row >= 0 and row <= ROW - 1 and col >= 0 and col <= COL - 1 and maze[row][col] != '0' and maze[row][col] != 'Y'

  42. #输出行走路线
  43. def printmaze(maze):
  44. for i in range(0,ROW):
  45. for j in range(0,COL):
  46. print(maze[i][j],end=" ")
  47. print()

  48. maze_puzzle(maze,0,0,ROW-1,COL-1)
  49. if find == False:
  50. print("未找到可行路线")


以上程序的执行结果均为:

成功走出迷宫,路线图为:

Y 0 Y Y Y

Y Y Y 0 Y

1 0 0 Y Y

1 0 0 Y 0

1 00 Y Y

多个 Y 组成的路线就是从起点到终点的可行路线。

相关文章
|
机器学习/深度学习 人工智能 算法
GSPO:Qwen让大模型强化学习训练告别崩溃,解决序列级强化学习中的稳定性问题
这是7月份的一篇论文,Qwen团队提出的群组序列策略优化算法及其在大规模语言模型强化学习训练中的技术突破
2212 0
GSPO:Qwen让大模型强化学习训练告别崩溃,解决序列级强化学习中的稳定性问题
|
JavaScript 中间件 测试技术
FastAPI全面指南:从入门到企业级应用实战
FastAPI正迅速成为Python Web开发领域的明星框架。它以高性能、高效率和现代化特性著称,性能媲美Go/Node.js,支持异步编程并内置自动化文档系统。本文全面解析FastAPI核心功能,包括类型安全路由、Pydantic数据验证、异步支持等,并通过实战案例展示其在RESTful API开发、微服务架构、实时数据处理及机器学习模型部署中的应用。同时,文章提供数据库集成、中间件配置和测试策略等最佳实践,解决常见问题并展望未来技术发展方向。掌握FastAPI,助你构建高效现代化Web应用。
2416 1
|
存储 Linux 内存技术
linux系统查看硬盘序列号
本文介绍在Linux系统中查看硬盘信息的三种方法:1) 使用`hdparm`工具,通过`sudo hdparm -i /dev/sda`获取硬盘序列号和型号;2) 使用`smartctl`工具,不仅可查序列号和型号,还能了解硬盘健康状态;3) 使用`lshw`命令显示存储设备拓扑信息。此外,提供通用技巧如用`lsblk`确认磁盘标识,及注意事项,例如管理员权限和云主机可能隐藏物理序列号等。
|
XML Java 开发者
通过springboot框架创建对象(一)
在Spring Boot中,对象创建依赖于Spring框架的核心特性——控制反转(IoC)和依赖注入(DI)。IoC将对象的创建和管理交由Spring应用上下文负责,开发者只需定义依赖关系。DI通过构造函数、setter方法或字段注入实现依赖对象的传递。Spring Boot的自动配置机制基于类路径和配置文件,自动为应用程序配置Spring容器,简化开发过程。Bean的生命周期包括定义扫描、实例化、依赖注入、初始化和销毁回调,均由Spring容器管理。这些特性提高了开发效率并简化了代码维护。
|
测试技术 Android开发 Python
python | 大麦网抢票(移动端)
上篇文章写到了使用windows11打开安卓应用,那么使用python来抢大麦网票应该也是可以的吧。库使用的是`pyautogui`。
2349 0
python | 大麦网抢票(移动端)
|
IDE 开发工具 C++
qt creator + vs2019编译记录
本文记录了作者在使用qt creator和vs2019编译项目时遇到的困难和解决方案,包括编译环境设置、qt creator编译脚本的成功案例、不带Ninja的编译脚本问题、错误示范以及相关参考链接。
980 0
qt creator + vs2019编译记录
|
运维 Oracle 关系型数据库
服务器数据恢复—浪潮服务器硬盘出现坏道的数据恢复案例
服务器数据恢复环境: 一台浪潮服务器中有一组由6块SAS硬盘组建的RAID。服务器上划分了1个卷,存放Oracle数据库文件。 服务器故障&检测: 服务器上有两个硬盘指示灯亮黄灯,RAID崩溃,服务器不可用。 将故障服务器中所有磁盘标记后取出。由硬件工程师检测故障服务器上的取出的6块硬盘是否存在硬件故障,经过检测发现变黄的指示灯所对应的2块硬盘存在坏道且SMART的错误冗余级别已经超过阈值。
|
传感器 PyTorch 数据处理
流式数据处理:DataLoader 在实时数据流中的作用
【8月更文第29天】在许多现代应用中,数据不再是以静态文件的形式存在,而是以持续生成的流形式出现。例如,传感器数据、网络日志、社交媒体更新等都是典型的实时数据流。对于这些动态变化的数据,传统的批处理方式可能无法满足低延迟和高吞吐量的要求。因此,开发能够处理实时数据流的系统变得尤为重要。
1136 1
|
人工智能 编解码 搜索推荐
AI绘画入门:从小白到入门,轻松玩转AI作画
随着AI技术的不断发展,AI绘画已经不再是遥不可及的梦想,它正逐渐走入大众视野,成为了一种新兴的艺术创作形式。即使没有绘画基础,你也可以通过AI工具轻松创作出精美的作品。本文将带你从小白入门,学习AI绘画的基础知识和操作技巧,让你快速体验AI绘画的乐趣。
1599 0
|
机器学习/深度学习 算法 数据可视化
面向萌新的数学建模入门指南
面向萌新的数学建模入门指南
1692 0