2013-11-03 167 views
0

我已成功完成迷宮的最短路徑算法(請參閱下面的代碼)。但是,我想將最短路徑的座標存儲到傳遞給我的函數的Stack參數中。有人能告訴我如何實現這一目標嗎? 下面是我對工作的迷宮:打印出最短路徑的所有單元格座標

注:1:長城,0:有效路徑,S:開始E:結束

String[][] map = new String[][] 
    { 
      new String[] { "1","1","1","0","0","0","1","1","1","1" }, 
      new String[] { "s","0","0","0","1","1","0","0","0","1" }, 
      new String[] { "1","1","0","0","1","0","0","1","0","1" }, 
      new String[] { "1","1","1","0","0","0","0","0","0","1" }, 
      new String[] { "1","0","1","1","1","0","1","1","0","1" }, 
      new String[] { "0","0","0","0","0","0","0","0","0","1" }, 
      new String[] { "0","1","1","1","1","1","1","1","1","1" }, 
      new String[] { "0","0","0","0","0","0","0","0","0","e" }, 
    }; 

我的算法:

// Pre-condition: Two integers indicating the row and col number to start from, 
// a 2d array of string objects representing the map of the maze, 
// a 2d array of booleans mapping out the visited cells in the maze 
// A string array containing the map of the maze. 
// An empty Stack object 
// Post-conditon: The distance of the shortest path from the current cell(start) 
// to the end of the maze 
public static int shortestPath(int row,int col,boolean[][] visited,String[][] map,Stack<Pair> path) 
{ 
    if(row < 0 || row >= map.length || col < 0 || col >= map[0].length) 
     return -1; 
    else if(visited[row][col] == true) 
     return -1; 
    else if(map[row][col].equals("e")) 
     return 0; 
    else 
    { 
     // Mark the current cell as visited 
     visited[row][col] = true; 

     // There is a wall 
     if(map[row][col].equals("1")) 
      return -1; 
     else 
     { 
      int[] pathDist = new int[4]; 

      // Start finding the path from the left 
      int left = 1 + shortestPath(row,col-1,visited,map,path); 

      // Start searching from the right 
      int right = 1 + shortestPath(row,col+1,visited,map,path); 

      // Start searching from the bottom 
      int down = 1 + shortestPath(row+1,col,visited,map,path); 

      // Start searching from the top 
      int up = 1 + shortestPath(row-1,col,visited,map,path); 

      visited[row][col] = false; 

      pathDist[0] = left; 
      pathDist[1] = right; 
      pathDist[2] = down; 
      pathDist[3] = up; 

      Arrays.sort(pathDist); 

      for(Integer i : pathDist) 
       if(i > 0) return i; 
      return -1; 
     } 
    } 
} 

}

回答

3

你的方法有一些根本性的錯誤:你計算所有通過迷宮的可能路徑,然後選擇最短的一個。試着改變你的輸入地圖

String[][] map = new String[][] { 
    new String[] { "s", "0", "0", "0", "0", "0", "0", "0", "0", "0" }, 
    new String[] { "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" }, 
    new String[] { "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" }, 
    new String[] { "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" }, 
    new String[] { "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" }, 
    new String[] { "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" }, 
    new String[] { "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" }, 
    new String[] { "0", "0", "0", "0", "0", "0", "0", "0", "0", "e" } }; 

,看看會發生什麼(算法將永遠不會終止,因爲可能路徑的數量是巨大的)。

最好使用某種Dijkstra's,其中您保留了距離開始位置的距離圖。

我介紹了一個方便的類Cell處理座標:

public static class Cell { 
    public int row;  
    public int col; 

    public Cell(int row, int col) { 
     this.row = row; 
     this.col = col;   
    } 

    @Override 
    public String toString() { 
     return "{" + row + ", " + col + "}"; 
    } 
} 

主要算法,根據Dijkstra的如下。它遵循麪包第一次遍歷迷宮,即首先在距離開始的距離1處訪問所有單元格,下一輪在距離開始處的距離2處訪問所有單元格,等等。

找到路徑是從結束單元格開始,然後緊跟着回到起始單元格的遞減距離。

public static int shortestPath(String[][] map, Cell start, Cell end, 
                  Stack<Cell> path) { 
    // initialize distances array filled with infinity 
    int[][] distances = new int[map.length][]; 
    for (int i = 0; i < map.length; i++) { 
     distances[i] = new int[map[i].length]; 
     Arrays.fill(distances[i], Integer.MAX_VALUE); 
    } 

    // the start node should get distance 0 
    int distance = 0; 
    List<Cell> currentCells = Arrays.asList(start); 

    while (distances[end.row][end.col] == Integer.MAX_VALUE 
       && !currentCells.isEmpty()) { 
     List<Cell> nextCells = new ArrayList<>(); 

     // loop over all cells added in previous round 
     // set their distance 
     // and add their neighbors to the list for next round 
     for (Cell cell : currentCells) { 
      if (distances[cell.row][cell.col] == Integer.MAX_VALUE 
        && !map[cell.row][cell.col].equals("1")) { 
       distances[cell.row][cell.col] = distance; 
       addNeighbors(cell, nextCells, map.length, map[0].length); 
      } 
     } 

     // prepare for next round 
     currentCells = nextCells; 
     distance++; 
    } 

    // find the path 
    if (distances[end.row][end.col] < Integer.MAX_VALUE) { 
     Cell cell = end; 
     path.push(end); 
     for (int d = distances[end.row][end.col]-1; d >= 0; d--) { 
      cell = getNeighbor(cell, d, distances); 
      path.push(cell); 
     } 
    } 

    return distances[end.row][end.col]; 
} 

我用幾個實用方法,以保持簡潔的算法:

// add all valid neighbors of a cell to the list 
    // where "valid" means: indices inside the maze 
private static void addNeighbors(Cell cell, List<Cell> list, 
             int maxRow, int maxCol) { 
    int[][] ds = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; 
    for (int[] d : ds) { 
     int row = cell.row + d[0]; 
     int col = cell.col + d[1];   
     if (isValid(row, col, maxRow, maxCol)) 
      list.add(new Cell(row, col)); 
    } 
} 

// find the neighbor of a cell having a certain distance from the start   
private static Cell getNeighbor(Cell cell, int distance, int[][] distances) { 
    int[][] ds = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; 
    for (int[] d : ds) { 
     int row = cell.row + d[0]; 
     int col = cell.col + d[1];   
     if (isValid(row, col, distances.length, distances[0].length) 
       && distances[row][col] == distance) 
      return new Cell(row, col);    
    } 
    return null; 
} 

// check if coordinates are inside the maze 
private static boolean isValid(int row, int col, int maxRow, int maxCol) { 
    return row >= 0 && row < maxRow && col >= 0 && col < maxCol; 
} 

我的主要方法如下

public static void main(String[] args) { 
    String[][] map = new String[][] 
      { 
        new String[] { "1","1","1","0","0","0","1","1","1","1" }, 
        new String[] { "s","0","0","0","1","1","0","0","0","1" }, 
        new String[] { "1","1","0","0","1","0","0","1","0","1" }, 
        new String[] { "1","1","1","0","0","0","0","0","0","1" }, 
        new String[] { "1","0","1","1","1","0","1","1","0","1" }, 
        new String[] { "0","0","0","0","0","0","0","0","0","1" }, 
        new String[] { "0","1","1","1","1","1","1","1","1","1" }, 
        new String[] { "0","0","0","0","0","0","0","0","0","e" }, 
      }; 

    Stack<Cell> path = new Stack<>(); 
    System.out.println(shortestPath(map, new Cell(1, 0), new Cell(7, 9), path)); 

    while (!path.isEmpty()) { 
     System.out.print(path.pop() + ", "); 
    } 
} 

,並打印

25 
{1, 0}, {1, 1}, {1, 2}, {1, 3}, {2, 3}, {3, 3}, {3, 4}, {3, 5}, {4, 5}, {5, 5}, 
{5, 4}, {5, 3}, {5, 2}, {5, 1}, {5, 0}, {6, 0}, {7, 0}, {7, 1}, {7, 2}, {7, 3}, 
{7, 4}, {7, 5}, {7, 6}, {7, 7}, {7, 8}, {7, 9}, 
1

您可以創建一個帶有兩個字段X和Y的新類Coordinate,您可以在其中存儲單元格的位置。然後,您可以將Coordinate s的列表作爲參數傳遞給您的函數。

雖然這不是最有效的方法。爲了獲得更好的性能,您可以使用前輩的矩陣。在這樣的矩陣中,您保留當前單元格的前一位置的信息。一個單元可以只有一個前導,而多個單元可以具有相同的。