从迷宫中找到最短路径(广度优先搜索)

时间:2017-09-24 18:24:07

标签: javascript algorithm

晚上好。我有一个以矩阵形式表示的迷宫。有一个起点和一个终点。我写了一个函数,它将所有可以访问的单元格添加到数组中。该函数还会删除所有没有后代的单元格(死锁)。但该功能不会删除导致死胡同的单元格。请帮助完成这项功能。

//maze
matrix = [
  [0, 1, 0, 1, 0],
  [0, 0, 1, 0, 0],
  [0, 0, 1, 1, 0],
  [0, 0, 0, 0, 0],
  [0, 1, 0, 1, 0]
];

var start = [4, 0];
var end = [3, 4];

function findWay(position, end) {

  var queue = [];

 //an array that contains the cells that have already visited
  var visited = []; 

 //An array that contains cells that can not be entered for this position
  var invalidCells = [];

 //mark the current cell with a unit so as not to visit it anymore.    
  matrix[position[0]][position[1]] = 1;

 //add the current position to the queue
  queue.push(position);

 //until the queue is empty    
  while (queue.length > 0) {

 //get the first element of the queue    
    var pos = queue.shift(); 


   //we clear the array, because for each new position we will have our own array    
    invalidCells.length = 0; 


   //an array of motion directions
    var direction = [
      [pos[0] + 1, pos[1]],
      [pos[0], pos[1] + 1],
      [pos[0] - 1, pos[1]],
      [pos[0], pos[1] - 1]
    ];                      

    for (var i = 0; i < direction.length; i++) {

//do a check for each direction
//if at least one cell does at least one of the conditions, the cell is 
  placed in an array of invalid cells 
//then run a new iteration of the loop

      if (direction[i][0] < 0 || direction[i][0] >= matrix[0].length || direction[i][1] < 0 || direction[i][1] >= matrix[0].length || matrix[direction[i][0]][direction[i][1]] != 0) { 

        invalidCells.push(direction[i]);
        continue;
      }

     //If this direction turned out to be an end cell
     //return the array of visited cells
      if (direction[i][0] == end[0] && direction[i][1] == end[1]) return visited;

     //if none of the conditions are met, mark this direction with one and add it to the end of the queue
      matrix[direction[i][0]][direction[i][1]] = 1;
      queue.push(direction[i]);
    }

    //add the current position to the array of visited cells
    visited.push(pos);

    //If no iteration of the loop returns anything, then this cell is a dead end
     if (invalidCells.length == 4) {

     //remove the deadlock from the array
      visited.pop();
    }
  }
}

findWay(start, end);

1 个答案:

答案 0 :(得分:1)

似乎没有必要跟踪visitedinvalidCells

  • visited包含所有访问过的单元格(在所有方向上)。虽然你到达死胡同后试图从中移除细胞,但是没有简单的方法可以回溯并从中移除其他细胞,导致这个死胡同,并且它们不会参与其他可能仍然存在的路径成功。

  • invalidCells仅用于检测死角,但由于前一点,我会放弃使用它。

我假设您的目标是到达一个visited数组,该数组代表结束单元格的最短路径,并从中删除所有可能的变体绕道。使用BFS实现这一目标的方法是使用您的队列不仅可以存储位置,还可以使用导致这些位置的最短路径。然后,当您点击结束单元格时,您可以返回该单个路径,忽略可能仍在队列中的所有其他路径。

请注意,您的示例存在问题:结束单元格标记为1,并且您的代码不会检测到此类单元格作为结束单元格,但会绕过它,并且永远不会找到它。要么确保结束单元始终标记为0,要么在进行任何其他检查之前执行结束单元测试。

以下是对您的代码所做的更改 - 请参阅注释的位置。

var matrix = [
  [0, 1, 0, 1, 0],
  [0, 0, 1, 0, 0],
  [0, 0, 1, 1, 0],
  [0, 0, 0, 0, 0],
  [0, 1, 0, 1, 0]
];

var start = [4, 0];
var end = [3, 4];

function findWay(position, end) {
  var queue = [];

  matrix[position[0]][position[1]] = 1;
  queue.push([position]); // store a path, not just a position

  while (queue.length > 0) {
    var path = queue.shift(); // get the path out of the queue
    var pos = path[path.length-1]; // ... and then the last position from it
    var direction = [
      [pos[0] + 1, pos[1]],
      [pos[0], pos[1] + 1],
      [pos[0] - 1, pos[1]],
      [pos[0], pos[1] - 1]
    ];

    for (var i = 0; i < direction.length; i++) {
      // Perform this check first:
      if (direction[i][0] == end[0] && direction[i][1] == end[1]) {
        // return the path that led to the find
        return path.concat([end]); 
      }
      
      if (direction[i][0] < 0 || direction[i][0] >= matrix[0].length 
          || direction[i][1] < 0 || direction[i][1] >= matrix[0].length 
          || matrix[direction[i][0]][direction[i][1]] != 0) { 
        continue;
      }

      matrix[direction[i][0]][direction[i][1]] = 1;
      // extend and push the path on the queue
      queue.push(path.concat([direction[i]])); 
    }
  }
}

var path = findWay(start, end);
console.log(JSON.stringify(path));