回溯法是一种不断试探且及时纠正错误的搜索方法,下面的求解过程采用回溯法。从入口出发,按某一方向向前探索,若能走通(未走过的),即某处可以到达,则到达一个新点,否则试探下一个方向;若所有的方向均没有通路,则沿原路返回前一点,换下一个方向继续试探,直到所有可能的通路都搜索到,或找到一条通路,或无路可走又返回到入口点。这里可以用一个栈来实现,每走一步,将该位置压入栈中,若该点无路可走,则出栈返回上一位置。

总结与思路:

一般的简单迷宫问题,类似于能否出去。可以使用“染色”的思路,一个节点被染红之后传给相邻的节点,最后如果出口节点也被染红,那么可以出去。从代码实现上看,

  1. 传入当前节点的信息,每次方法开始,判断是否为出口。是就可以提前退出,不是则继续向下执行。
  2. 建立迷宫大小的静态boolean数组,标识每个节点是否已被染色,避免死循环。
  3. 将本节点染色,判断是否有上下左右节点,有且未被染色,则调用本方法并传入将该节点信息(即递归调用)。
  4. 方法调用完毕,判断出口是否已经被染色。

复杂迷宫问题,查找最短路径等。

  1. 基本步骤同上,需注意几个问题。
  2. 考察最短路径,不同路径之间可以有一段重复。不应该再使用全局的Boolean数组。可以考虑使用List.contains()方法避免有重复的点。
  3. 需要保存路径时,使用回溯法。一般应使用stack,本题使用的是list,在执行下一次方法前将本节点加入list。然后一直向前探索,如果到了出口则保存下来,没到就不保存。递归方法返回时应该将本节点移除list,因为如果没到出口说明此路不通,无需保存本节点,如果到了出口,则已经加到result中了,不需要在保存本节点了。都应当移除,再从上一级节点探索。


遇到滴滴笔试题,

Java 迷宫问题Java 迷宫问题

[java] view plain copy
  1. import java.util.*;  
  2.   
  3. /** 
  4.  * @author XF 迷宫求路径,类似“染色” 
  5.  */  
  6. public class Main {  
  7.   
  8.     public static void main(String[] args) {  
  9.         Scanner sc = new Scanner(System.in);  
  10.         // 输入参数 测试:4 4 10 1 0 0 1 1 1 0 1 0 1 1 1 0 0 1 1  
  11.         int n = sc.nextInt();  
  12.         int m = sc.nextInt();  
  13.         int p = sc.nextInt();  
  14.         int[][] mi = new int[n][m];  
  15.         for (int i = 0; i < n; i++) {  
  16.             for (int j = 0; j < m; j++) {  
  17.                 mi[i][j] = sc.nextInt();  
  18.             }  
  19.         }  
  20.         flag = new boolean[n][m];  
  21.         List result = new ArrayList<>();  
  22.         List tempList = new ArrayList<>();  
  23.           
  24.         // 调用计算方法,传入参数。获得result.  
  25.         cc(00, mi, result, tempList);  
  26.   
  27.         // 比较消耗精力最少的  
  28.         int shortestNum = 0;  
  29.         List temp = (List) result.get(0);  
  30.         int min = (int) temp.get(temp.size() - 1);  
  31.         if (result.size() > 1) {  
  32.             for (int i = 1; i < result.size(); i++) {  
  33.                 temp = (List) result.get(i);  
  34.                 int tempMin = (int) temp.get(temp.size() - 1);  
  35.                 if (tempMin < min) {  
  36.                     min = tempMin;  
  37.                     shortestNum = i;  
  38.                 }  
  39.             }  
  40.         }  
  41.         List r = (List) result.get(shortestNum);  
  42.         r.remove(r.size() - 1);  
  43.         for(int i=0; i<r.size() ;i++){  
  44.             System.out.print(r.get(i)+",");  
  45.         }  
  46.         System.out.println("[0,3]");  
  47.           
  48.     }  
  49.   
  50.     // 辅助计算的静态变量  
  51.     static boolean[][] flag; // 为数组每个元素设置标志,避免重复到达某点造成多次计算或死循环  
  52.     static int pu; // pUsed 每个成功到达出口的序列计算消耗的体力值  
  53.   
  54.     /* 
  55.      * 计算迷宫路径方法,主要使用递归调用每个节点的上下左右。上下左右节点又可以调用它的上下左右。 按消耗体力的数量及出口位置,优先顺序为上、右、下、左 
  56.      * 传入参数,形参,即引用变量,地址不变,但指向的地址的值可以变化. 
  57.      */  
  58.     public static void cc(int i, int j, int[][] mi, List result, List tempList) {  
  59.         // flag[i][j] = true;  
  60.         // //本题是考察最短路径,不同路径之间可以有一段重复。应使用list.contains()判断是否已包含此节点。  
  61.         // 不管从哪条路到了出口,新建list存入结果,并保存pu  
  62.         if (i == 0 && j == mi[0].length - 1) {  
  63.             tempList.add(pu);  
  64.             result.add(new ArrayList<>(tempList));  
  65.             tempList.remove((Integer) pu);  
  66.         }  
  67.         /* 
  68.          * up,从当前节点,考虑向上。如果上个节点有且没有使用,将上个节点作为参数传入方法。其他同理。 
  69.          * 将当前节点信息(x,y)存入list,调用完方法移除!!!非常重要!!核心!! 
  70.          * 因为不管是否到达出口,都说明已经探索完从这个节点伸出的路径了,应当移除,则可以从此节点上个节点继续探索。 
  71.          * 到达了出口,已经保存了,该移除;没到,此路不通,移除。 根据需求应当使用stack,我使用不多就用list代替了。 
  72.          */  
  73.         if (i > 0 && mi[i - 1][j] == 1  
  74.                 && !tempList.contains("[" + (i - 1) + "," + j + "]")) {  
  75.             tempList.add("[" + i + "," + j + "]");  
  76.             pu += 3;  
  77.             cc(i - 1, j, mi, result, tempList);  
  78.             tempList.remove("[" + i + "," + j + "]");  
  79.             pu -= 3;  
  80.         }  
  81.         // right  
  82.         if (j < mi[0].length - 1 && mi[i][j + 1] == 1  
  83.                 && !tempList.contains("[" + i + "," + (j + 1) + "]")) {  
  84.             tempList.add("[" + i + "," + j + "]");  
  85.             pu += 1;  
  86.             cc(i, j + 1, mi, result, tempList);  
  87.             tempList.remove("[" + i + "," + j + "]");  
  88.             pu -= 1;  
  89.         }  
  90.         // down  
  91.         if (i < mi.length - 1 && mi[i + 1][j] == 1  
  92.                 && !tempList.contains("[" + (i + 1) + "," + j + "]")) {  
  93.             tempList.add("[" + i + "," + j + "]");  
  94.             cc(i + 1, j, mi, result, tempList);  
  95.             tempList.remove("[" + i + "," + j + "]");  
  96.         }  
  97.         // left  
  98.         if (j > 0 && mi[i][j - 1] == 1  
  99.                 && !tempList.contains("[" + i + "," + (j - 1) + "]")) {  
  100.             tempList.add("[" + i + "," + j + "]");  
  101.             pu += 1;  
  102.             cc(i, j - 1, mi, result, tempList);  
  103.             tempList.remove("[" + i + "," + j + "]");  
  104.             pu -= 1;  
  105.         }  
  106.     }  

相关文章:

猜你喜欢
  • 2022-12-23
  • 2022-02-06
  • 2022-12-23
  • 2022-01-26
相关资源
相似解决方案