2016-09-10 18 views
2

私は以下のコードを試しましたが、それは私に正しい答えを与えませんでした。鍵と扉を持つパズルの最短経路を見つける方法

ここに問題文があります。

2-Dグリッドがあるとします。各ポイントは土地または水のいずれかです。そこには も出発点と目標です。

ドアを開くキーがあります。各キーは1つの ドアに対応しています。

土地のタイル、キー、ドアを使用して目標から までの最短経路を返す関数を実装します。

データ表現

マップは文字列の配列として渡されます。

マップには次のタイルを配置できます。

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

名前はdoesnのため、あなたの問題は、(非常に悪い名前ですhm変数によってを追跡visited追跡およびロックされたドアの悪い実装の組み合わせで管理されます変数が何であるかを理解するのを助ける)

あなたの小さなロボットは、多くの場合、何度も何度も前後に歩いているの追跡訪問しました。あなたがへのデバッグのためにprint文を挿入した場合たとえば、:

  • トラックと印刷前方のステップの総数は、短いパスが
  • 印刷最長のを発見された時はいつでもゴールに
  • 印刷最短経路を試してみました

    01:パスが長いパスが!が歩いた長いパスを意味しますが、次のような結果を得る

を、発見され、そして*が見つかっ目標に短いパスを意味するたびにしようとしました撮影した前方のステップの

 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-> 

総数:390236

は最長パスが前後に多くのことを行っている。

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(土地)に変更して、鍵に合ったすべてのドアのロックを解除します。バックトラックすると、すべてのドアが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に戻ってそこから目的地まで直接歩くと、のドアはキーを持っていてもになります。

これは、キーが2回あることがわからないためです。

ソリューション

あなただけの訪問追跡を修正した場合、あなたが二度同じキーを踏まないので、あなたのコードは、動作します。

ロックされたドアトラッキングを修正するだけで、同じキーが複数コピーされていることを確認すると、ドアを再び早期にロックしないため、コードが機能します。

しかし、あなたの改訂解決のために次の点を考慮してください

  • 同じキーのものよりも実際に多くのがある場合はどう?
  • 新しい鍵を持っていない限り、場所を繰り返し訪問しないでください。
  • これまでに発見された最短経路よりも長い経路上にいる場合、歩行を続けないでください。

これを別の方法で実行する方法の1つは、実際にどのように動作するかを考えることです。 1)ドアがまだどこにあるかを必ずしも知っているわけではなく、2)立っている場所からドアに手を出すことができないため、キーを見つけたらドアのロックを解除しないでください。

代わりにキーリングを付けてください。あなたが持っていないキーに遭遇したら、それをキーリングに追加します。キーリングに新しいキーを追加すると、以前に歩いたエリアに再度訪問することもできます。ドアに出会ったら、キーリングにキーがあればそれを歩くことができます。

可能なキーは26個あるため、32ビットのintの値をキーリングにすることができます。

可能な/関連するすべてのパスをチェックするのに90ステップ(現在のコードの390236ステップではない)しかかからないサンプル実装の場合はIDEONEを参照してください。

+0

ありがとうございました!!!!あなたの詳細な解説と解決策を使って、あなたが指摘した考えを持っていると思います。この質問では、キーを取得したときに訪問したボードをリフレッシュし、すべてのキーを格納するためにintを使用しました。これも本当に良い解決策です。再度、感謝します!私は本当に多くを学んだ:) – yilia

関連する問題