贪吃的小老鼠又回来了,这次有什么新的办法吃到奶酪呢?

规则不变,只能上下左右在格子内移动。

因为上次的深度优先算法让老鼠走了不少冤枉路,这次老鼠带来了帮手探路鼠。探路鼠的使用规则如下:

小老鼠按右、下、左、上的顺序向身边四个格子尝试放出探路鼠,如果遇到猫、出边界、已经有探路鼠存在的格子则放弃。

每只探路鼠都有唯一的顺序号,第一只从1开始,每放成功一只序号递增1。

老鼠探路完成后,找出当前未行动过的顺序号最小的探路鼠重复老鼠的工作,即尝试向右、下、左、上四个格子放出探路鼠。

用图来解释一下,第一步,小老鼠放出两只探路鼠,如下:

老鼠行动完成,按规则是1号探路鼠行动。由于地形所限,1号尝试了右、下、左、上四个方向后,只成功放出了3号。

1号完成后,轮到2号行动,也只成功放出一只,即4号

据此规则不难推算出,接下来依次是:

3号放出5号

4号放出6号

5号放出7号

6号放出8号

7号放出9、10号

8号放出11号

9号放出12号

如下图:

注意12号探路鼠首先发现了奶酪,这时它向上一级即9号汇报,9号向7号汇报。。。,12->9->7->5->3->1->老鼠,可以计算出最少的步数是6。

上面的探路过程即广度优先搜索(Breadth First Search, BFS),与深度优先搜索的一条路走到黑不同,每到一个新的位置都向四个方向分别探索,找出每一个分支,并对每一个分支继续探索。

用程序来描绘这一过程,首先需要把迷宫“数字化“,如下图:

这样就可以用一个二维数组存储迷宫:

  1. int width = 5;  //迷宫宽度
  2. int height = 4;  //迷宫高度
  3. int[][] maze = new int[width][height];
  4. maze[2][0] = 1;
  5. maze[1][2] = 1;
  6. maze[2][2] = 1;
  7. maze[4][1] = 1;

用一个同样大小的二维数组标记已经放了探路鼠的点

  1. int[][] mark = new int[width][height];
  2. mark[0][0] = 1;

每个“探路鼠”需要知道自己所在位置(坐标),自己的上一级是谁。为了方便,还用它记录了到达该位置需要的步数。用一个类来表示:

  1. static class Trace {
  2. public Trace(int x, int y, int father, int step) {
  3. this.x = x;
  4. this.y = y;
  5. this.father = father;
  6. this.step = step;
  7. }
  8. private int x;
  9. private int y;
  10. private int father;
  11. private int step;
  12. public int getX() {
  13. return x;
  14. }
  15. public void setX(int x) {
  16. this.x = x;
  17. }
  18. public int getY() {
  19. return y;
  20. }
  21. public void setY(int y) {
  22. this.y = y;
  23. }
  24. public int getFather() {
  25. return father;
  26. }
  27. public void setFather(int father) {
  28. this.father = father;
  29. }
  30. public int getStep() {
  31. return step;
  32. }
  33. public void setStep(int step) {
  34. this.step = step;
  35. }
  36. @Override
  37. public String toString() {
  38. return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
  39. }
  40. }

完整代码如下:

  1. import org.apache.commons.lang3.builder.ToStringBuilder;
  2. import org.apache.commons.lang3.builder.ToStringStyle;
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. /**
  6. * 老鼠走迷宫 BFS算法
  7. * Created by autfish on 2016/9/5.
  8. */
  9. public class BfsRatMaze {
  10. int min = Integer.MAX_VALUE;
  11. int endX = 4;  //目标点横坐标
  12. int endY = 2;  //目标点纵坐标
  13. int width = 5;  //迷宫宽度
  14. int height = 4;  //迷宫高度
  15. int[][] maze;
  16. int[][] mark;
  17. static class Trace {
  18. public Trace(int x, int y, int father, int step) {
  19. this.x = x;
  20. this.y = y;
  21. this.father = father;
  22. this.step = step;
  23. }
  24. private int x;
  25. private int y;
  26. private int father;
  27. private int step;
  28. public int getX() {
  29. return x;
  30. }
  31. public void setX(int x) {
  32. this.x = x;
  33. }
  34. public int getY() {
  35. return y;
  36. }
  37. public void setY(int y) {
  38. this.y = y;
  39. }
  40. public int getFather() {
  41. return father;
  42. }
  43. public void setFather(int father) {
  44. this.father = father;
  45. }
  46. public int getStep() {
  47. return step;
  48. }
  49. public void setStep(int step) {
  50. this.step = step;
  51. }
  52. @Override
  53. public String toString() {
  54. return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
  55. }
  56. }
  57. public void bfs() {
  58. int[][] next = new int[][] { //按右->下->左->上的顺序尝试
  59. {1, 0},
  60. {0, 1},
  61. {-1, 0},
  62. {0, -1}
  63. };
  64. int head = 0, tail = 1;
  65. int startX = 0, startY = 0;
  66. int nextX, nextY;
  67. List<Trace> traces = new ArrayList<>();
  68. traces.add(head, new Trace(startX, startY, -1, 0));
  69. mark[startX][startY] = 1;
  70. int flag = 0;
  71. while(head < tail) {
  72. for(int k = 0; k <= 3; k++) {
  73. nextX = traces.get(head).getX() + next[k][0];
  74. nextY = traces.get(head).getY() + next[k][1];
  75. if(nextX < 0 || nextX >= width || nextY < 0 || nextY >= height) {  //超出边界
  76. continue;
  77. }
  78. //没有障碍且没有探索过, 则把当前位置标记为未探索点
  79. if(maze[nextX][nextY] == 0 && mark[nextX][nextY] == 0) {
  80. this.mark[nextX][nextY] = 1;
  81. traces.add(tail, new Trace(nextX, nextY, head, traces.get(head).getStep() + 1));
  82. tail++;
  83. }
  84. if(nextX == endX && nextY == endY) {
  85. flag = 1;
  86. break;
  87. }
  88. }
  89. if(flag == 1)
  90. break;
  91. //一个点的四个方向探索完成, 取编号最小的一个未探索点
  92. head++;
  93. }
  94. Trace end = traces.get(tail - 1);
  95. int father = end.getFather();
  96. System.out.println("共" + end.getStep() + "步");
  97. StringBuilder path = new StringBuilder();
  98. path.insert(0, "->[" + end.getX() + "," + end.getY() + "]");
  99. while(father >= 0) {
  100. Trace prev = traces.get(father);
  101. father = prev.getFather();
  102. if(father > -1)
  103. path.insert(0, "->[" + prev.getX() + "," + prev.getY() + "]");
  104. else
  105. path.insert(0, "[" + prev.getX() + "," + prev.getY() + "]");
  106. }
  107. System.out.println(path.toString());
  108. }
  109. public void initMaze() {
  110. this.maze = new int[width][height];
  111. this.mark = new int[width][height];
  112. this.maze[2][0] = 1;
  113. this.maze[1][2] = 1;
  114. this.maze[2][2] = 1;
  115. this.maze[4][1] = 1;
  116. this.mark[0][0] = 1;
  117. //打印迷宫 _表示可通行 *表示障碍 !表示目标
  118. for(int y = 0; y < height; y++) {
  119. for(int x = 0; x < width; x++) {
  120. if(x == endX && y == endY) {
  121. System.out.print("!  ");
  122. }  else if(this.maze[x][y] == 1) {
  123. System.out.print("*  ");
  124. } else {
  125. System.out.print("_  ");
  126. }
  127. }
  128. System.out.println();
  129. }
  130. System.out.println();
  131. }
  132. public static void main(String[] args) {
  133. BfsRatMaze b = new BfsRatMaze();
  134. b.initMaze();
  135. b.bfs();
  136. }
  137. }

运行结果:

  1. _  _  *  _  _
  2. _  _  _  _  *
  3. _  *  *  _  !
  4. _  _  _  _  _
  5. 共6步
  6. [0,0]->[1,0]->[1,1]->[2,1]->[3,1]->[3,2]->[4,2]

用深度优先搜索的程序见:

Java与算法之(12) - 老鼠再闯迷宫(广度优先算法)的更多相关文章

  1. [转载]java面试中经常会被问到的一些算法的问题

    Java面试中经常会被问到的一些算法的问题,而大部分算法的理论及思想,我们曾经都能倒背如流,并且也能用开发语言来实现过, 可是很多由于可能在项目开发中应用的比较少,久而久之就很容易被忘记了,在此我分享 ...

  2. 【SSL1455&1456】 电子老鼠闯迷宫 & 骑士游行

    考点概况: 广搜板子 题面: \[\Large\text{电子老鼠闯迷宫}\] \[Time~Limit:1000MS~~Memory~Limit:65536K\] Description 如下图12 ...

  3. Java Web 深入分析(12) JVM(2) 垃圾收集与内存分配

    前言 java的内存分配和垃圾回收往往是影响系统性能和并发能力的主要因素,虚拟机提供许多的参数就是为了根据不同环境和请教下进行调优,没有最好的调优也没有固定的调优.需要我们深入的去了解jvm的各个垃圾 ...

  4. Java 中级 学习笔记 2 JVM GC 垃圾回收与算法

    前言 在上一节的学习中,已经了解到了关于JVM 内存相关的内容,比如JVM 内存的划分,以及JDK8当中对于元空间的定义,最后就是字符串常量池等基本概念以及容易混淆的内容,我们都已经做过一次总结了.不 ...

  5. [BFS]电子老鼠闯迷宫

    电子老鼠闯迷宫 Description 如下图12×12方格图,找出一条自入口(2,9)到出口(11,8)的最短路径. Input Output Sample Input 12 //迷宫大小 2 9 ...

  6. C++、Java、Python、Linux、Go、前端、算法,慕课资料分享

    C++.Java.Python.Linux.Go.前端.算法,慕课资料分享 微信公众号:大道同行JAVA 如有问题或建议,请后台留言,我会尽力解决你的问题. 前言 又见面了.废话不多说,最近多了一些在 ...

  7. Java设计模式(十三) 别人再问你设计模式,叫他看这篇文章

    原创文章,转载请务注明出处 OOP三大基本特性 封装 封装,也就是把客观事物封装成抽象的类,并且类可以把自己的属性和方法只让可信的类操作,对不可信的进行信息隐藏. 继承 继承是指这样一种能力,它可以使 ...

  8. 201521123082 《Java程序设计》第12周学习总结

    201521123082 <Java程序设计>第12周学习总结 标签(空格分隔): java 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. An ...

  9. 201521123067 《Java程序设计》第12周学习总结

    201521123067 <Java程序设计>第12周学习总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 书面作业 将Student对 ...

随机推荐

  1. 使用MyBatis缓存

    (1).为什么需要使用缓存:: MyBatis是一个持久层(数据库层)映射框架,在所有访问数据库的操作中,无疑数据查询是最耗费数据库资源的操作了,因为你一次可能需要查询成千上百万条记录(如果你不加限制 ...

  2. echarts异步数据加载(在下拉框选择事件中异步更新数据)

    接触echarts 大半年了,从不会到熟练也做过不少的图表,隔了一段时间没使用这玩意,好多东西真心容易忘了.在接触echarts这期间也没有总结什么东西,今天我就来总结一下如何在echart中异步加载 ...

  3. bzoj 3531: [Sdoi2014]旅行

    Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰. ...

  4. NET Framework 版本和依赖关系

    原文:https://docs.microsoft.com/zh-cn/dotnet/framework/migration-guide/versions-and-dependencies 每个版本的 ...

  5. CentOS7源码安装lamp

    环境介绍 虚拟机 : VMware Workstation 14 Pro 镜像 : CentOS Linux release 7.4.1708 (Core) 物理机 : windows 7 64位 防 ...

  6. SQL2005 到 SQL2008R2 发布订阅----发布'xxxxx'的初始快照尚不可用。

    步骤略! SQL2005 到 SQL2008R2 发布订阅----发布'xxxxx'的初始快照尚不可用. 发布库快照已经创建完成为什么到订阅就快照不可用呢! 订阅通过日志读取代理解析! 查了下代理安全 ...

  7. 只要发生ajax请求时加载旋转的按钮

    定义一个变量 全局 c 只要发生ajax时给c++ 当ajax请求success或者error时,c--; 对加载的按钮添加个事件   监听 c  如果c得值没变化  则隐藏按钮   如果变化了则显示 ...

  8. cobbler自动安装系统(Centos7.X)

    环境: [root@kickstart ~]# cat /etc/redhat-release CentOS Linux release (Core) [root@kickstart ~]# unam ...

  9. 基于IndexedDB实现简单文件系统

    现在的indexedDB已经有几个成熟的库了,比如西面这几个,任何一个都是非常出色的. 用别人的东西好处是上手快,看文档就好,要是文档不太好,那就有点尴尬了. dexie.js :A Minimali ...

  10. 关于css那些常用却有点记不住的属性

    虽然说css样式都比较简单,但是某些单词每次都用到还是没记住怎么拼写,都要百度一番,干脆就汇总一下自己经常忘记的这些,也好方便查找. 单行文本溢出: { overflow: hidden; text- ...