zoukankan      html  css  js  c++  java
  • Java与算法之(12)

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

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

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

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

    每只探路鼠都有唯一的顺序号,第一只从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),与深度优先搜索的一条路走到黑不同,每到一个新的位置都向四个方向分别探索,找出每一个分支,并对每一个分支继续探索。

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

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

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. int width = 5;  //迷宫宽度  
    2. int height = 4;  //迷宫高度  
    3.           
    4. int[][] maze = new int[width][height];  
    5.           
    6. maze[2][0] = 1;  
    7. maze[1][2] = 1;  
    8. maze[2][2] = 1;  
    9. maze[4][1] = 1;  

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

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. int[][] mark = new int[width][height];  
    2. mark[0][0] = 1;  

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

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. static class Trace {  
    2.   
    3.     public Trace(int x, int y, int father, int step) {  
    4.         this.x = x;  
    5.         this.y = y;  
    6.         this.father = father;  
    7.         this.step = step;  
    8.     }  
    9.   
    10.     private int x;  
    11.     private int y;  
    12.     private int father;  
    13.     private int step;  
    14.   
    15.     public int getX() {  
    16.         return x;  
    17.     }  
    18.   
    19.     public void setX(int x) {  
    20.         this.x = x;  
    21.     }  
    22.   
    23.     public int getY() {  
    24.         return y;  
    25.     }  
    26.   
    27.     public void setY(int y) {  
    28.         this.y = y;  
    29.     }  
    30.   
    31.     public int getFather() {  
    32.         return father;  
    33.     }  
    34.   
    35.     public void setFather(int father) {  
    36.         this.father = father;  
    37.     }  
    38.   
    39.     public int getStep() {  
    40.         return step;  
    41.     }  
    42.   
    43.     public void setStep(int step) {  
    44.         this.step = step;  
    45.     }  
    46.   
    47.     @Override  
    48.     public String toString() {  
    49.         return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);  
    50.     }  
    51. }  

    完整代码如下:

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

    运行结果:

    [java] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. _  _  *  _  _    
    2. _  _  _  _  *    
    3. _  *  *  _  !    
    4. _  _  _  _  _    
    5.   
    6. 6步  
    7. [0,0]->[1,0]->[1,1]->[2,1]->[3,1]->[3,2]->[4,2]  

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

  • 相关阅读:
    thread_Semaphore信号量
    c 语言文本文件判断是否到达结尾的问题
    c语言快速排序算法(转)
    c语言双向循环链表
    gtk+学习笔记(八)
    c语言循环链表的问题
    linux c获取本地时间
    gtk+学习笔记(七)
    gtk+学习笔记(六)
    gtk+学习笔记(五)
  • 原文地址:https://www.cnblogs.com/sa-dan/p/6837090.html
Copyright © 2011-2022 走看看