2016-09-10 24 views
2

我试过下面的代码,但它没有给我正确的答案。如何在钥匙和门的拼图中找到最短路径

这是问题陈述。

假设你有一个2-D网格。每个点都是土地或水。 也是一个起点和目标。

现在有钥匙可以打开门。每个钥匙对应一个 门。

实现,使用土地的瓷砖,钥匙开门返回 的目标从一开始的最短路径的功能。

数据表示法

该映射将作为字符串数组传递。

一张地图可以有以下图块。

0 = Water1 = Land2 = Start3 = Goaluppercase = door lowercase = key

网格可以是这样的:

  {{'0', '2', '1', '1', '1'}, 
      {'0', '1', '0', '0', '1'}, 
      {'0', '0', '0', '0', '1'}, 
      {'0', '0', 'A', '0', '1'}, 
      {'1', '1', 'a', '1', '1'}, 
      {'1', 'b', '0', '0', 'B'}, 
      {'1', '1', '0', '0', '1'}, 
      {'0', '1', '0', '0', '3'}}; 

所以最短路径应该是: 01-> 02-> 03-> 04-> 14 →24→34→44→43→42→41→51→41→42→43→44→54→64→74

我的代码去像:

public class shortestPath { 
    static int shortest = Integer.MAX_VALUE; 
    static String path = ""; 
    static ArrayList<ArrayList<int[]>> res = new ArrayList<ArrayList<int[]>>(); 

    public static void main(String[] args) { 
     char[][] board = {{'0', '2', '1', '1', '1'}, 
       {'0', '1', '0', '0', '1'}, 
       {'0', '0', '0', '0', '1'}, 
       {'0', '0', 'A', '0', '1'}, 
       {'1', '1', 'a', '1', '1'}, 
       {'1', 'b', '0', '0', 'B'}, 
       {'1', '1', '0', '0', '1'}, 
       {'0', '1', '0', '0', '3'}}; 
     System.out.println(findShortest(board)); 
     System.out.println(path); 

    } 

    public static int findShortest(char[][] board) { 
     if (board == null || board.length == 0 || board[0].length == 0) return 0; 
     int row = board.length; 
     int col = board[0].length; 
     int[] start = new int[2]; 
     int[] end = new int[2]; 
     int[][] visited = new int[row][col]; 
     HashMap<Character, ArrayList<int[]>> hm = new HashMap<>(); 
     for (int i = 0; i < row; i++) { 
      for (int j = 0; j < col; j++) { 
       if (board[i][j] == '2') { 
        start = new int[]{i, j}; 
       } 
       if (board[i][j] == '3') { 
        end = new int[]{i, j}; 
       } 
       if (Character.isUpperCase(board[i][j])) { 
        char key = Character.toLowerCase(board[i][j]); 
        if (hm.containsKey(key)) { 
         hm.get(key).add(new int[]{i, j}); 
        } else { 
         ArrayList<int[]> al = new ArrayList<>(); 
         al.add(new int[]{i, j}); 
         hm.put(key, al); 
        } 
        board[i][j] = '0'; 
       } 
      } 
     } 
     //HashSet<Character> hs = new HashSet<Character>(); 
     //helper2(board, hs, start[0], start[1], row, col, 0, visited, new StringBuilder(), new ArrayList<int[]>(), res); 
     helper(board, hm, start[0], start[1], row, col, 0, visited, new StringBuilder()); 
     return shortest; 
    } 

    public static void helper(char[][] board, HashMap<Character, ArrayList<int[]>> hm, int r, int c, int row, int col, int count, int[][] visited, StringBuilder sb) { 
     // System.out.println(r + " " + c); 
     visited[r][c] = visited[r][c] + 1; 
     sb.append(r).append(c).append("->"); 
     if (board[r][c] == '3') { 
      System.out.println(count); 
      if (shortest > count) { 
       path = sb.deleteCharAt(sb.length() - 1).deleteCharAt(sb.length() - 1).toString(); 
       sb.append("->"); 
       shortest = count; 
      } 
      //return; 
      //shortest = Math.min(shortest, count); 
     } 
     if (Character.isLowerCase(board[r][c])) { // if this is the key; 
      if (hm.containsKey(board[r][c])) { 
       for (int[] i : hm.get(board[r][c])) { 
        board[i[0]][i[1]] = '1'; 
       } 
      } 
     } 
     if (r + 1 < row && board[r + 1][c] != '0' && visited[r + 1][c] < 2) { 
      helper(board, hm, r + 1, c, row, col, count + 1, visited, sb); 
     } 
     if (c + 1 < col && board[r][c + 1] != '0' && visited[r][c + 1] < 2) { 
      helper(board, hm, r, c + 1, row, col, count + 1, visited, sb); 
     } 
     if (r - 1 >= 0 && board[r - 1][c] != '0' && visited[r - 1][c] < 2) { 
      helper(board, hm, r - 1, c, row, col, count + 1, visited, sb); 
     } 
     if (c - 1 >= 0 && board[r][c - 1] != '0' && visited[r][c - 1] < 2) { 
      helper(board, hm, r, c - 1, row, col, count + 1, visited, sb); 
     } 
     visited[r][c] = visited[r][c] - 1; 
     sb.delete(sb.length() - 4, sb.length()); 
     if (Character.isLowerCase(board[r][c])) { // if this is the key; 
      if (hm.containsKey(board[r][c])) { 
       for (int[] i : hm.get(board[r][c])) { 
        board[i[0]][i[1]] = '0'; 
       } 
      } 
     } 
     return; 
    } 


} 
+1

你做了什么**你得到答案?你是否已经通过调试器完成了你的算法? –

+1

使用调试器确实是解决此问题的唯一好方法。我怀疑有太多的代码可以让任何人通过阅读来发现错误。 –

回答

3

你的问题是一个糟糕的执行visited跟踪的组合和上锁的门跟踪(由hm变量,这是一个非常不好的名字管理,起名字没有按无助于理解变量是什么)

访问的追踪

你的小机器人经常来回走动一遍又一遍。例如,如果您插入打印语句调试:

  • 跟踪和打印的前进的总步数试图
  • 打印的最短路径,目标只要一个较短的路径发现
  • 打印最长路径尝试每当一个较长的路径被发现

会得到以下结果,其中!意味着走更长的路,并*手段,目标路径较短发现:

 1: ! 01-> 
    2: ! 01->11-> 
    3: ! 01->11->01-> 
    4: ! 01->11->01->11-> 
    6: ! 01->11->01->02->03-> 
    7: ! 01->11->01->02->03->04-> 
    8: ! 01->11->01->02->03->04->14-> 
    9: ! 01->11->01->02->03->04->14->24-> 
    10: ! 01->11->01->02->03->04->14->24->34-> 
    11: ! 01->11->01->02->03->04->14->24->34->44-> 
    12: ! 01->11->01->02->03->04->14->24->34->44->34-> 
    13: ! 01->11->01->02->03->04->14->24->34->44->34->44-> 
    14: ! 01->11->01->02->03->04->14->24->34->44->34->44->43-> 
    15: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42-> 
    16: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42->43-> 
    17: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42->43->42-> 
    18: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42->43->42->32-> 
    20: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42->43->42->41->51-> 
    21: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42->43->42->41->51->61-> 
    22: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42->43->42->41->51->61->71-> 
    23: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42->43->42->41->51->61->71->61-> 
    24: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42->43->42->41->51->61->71->61->71-> 
    26: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42->43->42->41->51->61->71->61->51->41-> 
    27: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42->43->42->41->51->61->71->61->51->41->40-> 
    28: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42->43->42->41->51->61->71->61->51->41->40->50-> 
    29: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42->43->42->41->51->61->71->61->51->41->40->50->60-> 
    30: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42->43->42->41->51->61->71->61->51->41->40->50->60->50-> 
    31: ! 01->11->01->02->03->04->14->24->34->44->34->44->43->42->43->42->41->51->61->71->61->51->41->40->50->60->50->60-> 
    9577: * 01->11->01->02->03->04->14->24->34->44->43->42->41->51->61->71->61->51->41->42->43->44->54->64->74-> 
    9611: ! 01->11->01->02->03->04->14->24->34->44->43->42->41->51->61->71->61->51->50->60->50->40->41->42->43->44->54->64->74-> 
    9612: ! 01->11->01->02->03->04->14->24->34->44->43->42->41->51->61->71->61->51->50->60->50->40->41->42->43->44->54->64->74->64-> 
    9613: ! 01->11->01->02->03->04->14->24->34->44->43->42->41->51->61->71->61->51->50->60->50->40->41->42->43->44->54->64->74->64->74-> 
    9623: ! 01->11->01->02->03->04->14->24->34->44->43->42->41->51->61->71->61->51->50->60->50->40->41->42->43->44->34->24->14->04->03->02-> 
    9901: * 01->11->01->02->03->04->14->24->34->44->43->42->41->51->61->51->41->42->43->44->54->64->74-> 
19141: ! 01->11->01->02->03->04->14->24->34->24->34->44->43->42->41->51->61->71->61->51->50->60->50->40->41->42->43->44->54->64->74->64->74-> 
53941: ! 01->11->01->02->03->04->14->04->14->24->34->24->34->44->43->42->41->51->61->71->61->51->50->60->50->40->41->42->43->44->54->64->74->64-> 
53942: ! 01->11->01->02->03->04->14->04->14->24->34->24->34->44->43->42->41->51->61->71->61->51->50->60->50->40->41->42->43->44->54->64->74->64->74-> 
145776: ! 01->11->01->02->03->02->03->04->14->04->14->24->34->24->34->44->43->42->41->51->61->71->61->51->50->60->50->40->41->42->43->44->54->64->74->64-> 
145777: ! 01->11->01->02->03->02->03->04->14->04->14->24->34->24->34->44->43->42->41->51->61->71->61->51->50->60->50->40->41->42->43->44->54->64->74->64->74-> 
158937: * 01->02->03->04->14->24->34->44->43->42->41->51->61->51->41->42->43->44->54->64->74-> 

的向前档总数采取:

即最长路径来回很多:

01->11-> 
01->02->03-> 
    02->03->04->14-> 
      04->14->24->34-> 
        24->34->44->43->42->41->51->61->71->61-> 
              51->50->60-> 
               50->40->41->42->43->44->54->64->74-> 
                      64->74-> 

这是一个很大浪费行走。

锁着的门跟踪

重温你的逻辑:你开始改变所有门0(水)。当你遇到钥匙时,通过将板子值更改为1(Land),可以解锁所有适合钥匙的门。回溯时,您可以更改所有的门回到0(水)。

现在来看看解决您的代码想出了:

01->02->03->04->14->24->34->44->43->42->41->51->61-> 
              51->41->42->43->44->54->64->74 

问题是,关键是51,所以当代码从该解决方案在回溯了51,关闭门,这样,当它得到回到第一51,并尝试直接从那里步行到目标,门关闭,即使你有钥匙。

那是因为你不知道你有键两次。

解决方案

如果你只是修复走访跟踪,你的代码将工作,因为你不会在同一个关键步骤两次。

如果你只是修复锁着的门跟踪,即跟踪你有相同的密钥的多个副本,你的代码将工作,因为你不会过早地再次锁门。

然而,考虑为修订的解决方案如下:

  • 如果确实有相同的密钥的不止一个?
  • 不要重复访问一个位置,除非你拿起一个新的密钥。
  • 不要继续走,如果你是一个已经超过迄今为止发现的最短路径到目标的路径上。

所以,一种不同的方法是想想它在现实生活中会如何工作。当你找到钥匙时,你不会解锁门,因为1)你不一定知道门在哪里,2)你不能从你站立的地方到达门。

相反,保持一个钥匙圈。当你遇到一个你没有的钥匙时,将它添加到钥匙圈。向密钥环添加新密钥还意味着您可以重新访问先前步行的区域。当你遇到门时,如果钥匙圈中有钥匙,可以穿过它。

由于有26个可能的密钥,因此具有32位的int值可以是您的密钥环。

请参阅IDEONE以获取仅执行90个步骤(而不是您当前代码的390236步骤)以检查所有可能/相关路径的样本实施。

+0

非常感谢!!!!有了您的详细解释和解决方案,我想我已经明白了您的想法。对于这个问题,重要的一步是刷新访问板,当你得到一个密钥,并且使用int来存储所有密钥时,这也是一个非常好的解决方案!再次感谢!我真的学到了很多:) – yilia