使用广度优先搜索算法存储迷宫求解路径

问题描述

我正在使用广度优先搜索算法来解决迷宫问题。我的算法成功找到了最短路径,但没有存储最短路径。它只是告诉我完成此路径的步骤数,但会保存所有已检查的正方形,无论它们是否属于最短路径。我确实尝试了很多方法来存储最短路径,但是在路径中出现错误,其中还包括了不在最短路径中的正方形。如果可以找到我,可以将最短路径存储在ArrayList或ArrayQueue或array或其他任何东西中的方法。 CorrectPath()是我所做的,因此我可以确定最短路径中的正方形,但这是错误的。我不认为这太复杂了,只是我不知道该怎么做。谢谢您的时间。

平方具有x和y位置以及到目标的距离作为属性

public class BreathAlgorithm {
// Java program to find the shortest path between a given source cell to a destination cell.
static int ROW;
static int COL;
// These arrays are used to get row and column numbers of 4 neighbours of a given cell
static int[] rowNum = {-1,1};
static int[] colNum = {0,-1,1,0};

// check whether given cell (row,col) is a valid cell or not.
static boolean isValid(int row,int col)
{
    // return true if row number and column number is in range
    return (row > 0) && (row <= ROW) && (col > 0) && (col <= COL);
}

// Checks if a square is an adjacent to another square
static boolean isNearSquare(Square a,Square b){
    int x = 1;
    int y = 0;
    if((Math.abs((a.getX()+x) - (b.getX()+x))) + (Math.abs((a.getY()+y) - (b.getY()+y))) != 1){
        return false;
    }
    x = -1;
    y = 0;
    if((Math.abs((a.getX()+x) - (b.getX()+x))) + (Math.abs((a.getY()+y) - (b.getY()+y))) != 1){
        return false;
    }
    x = 0;
    y = 1;
    if((Math.abs((a.getX()+x) - (b.getX()+x))) + (Math.abs((a.getY()+y) - (b.getY()+y))) != 1){
        return false;
    }
    x = 0;
    y = -1;
    return (Math.abs((a.getX() + x) - (b.getX() + x))) + (Math.abs((a.getY() + y) - (b.getY() + y))) == 1;
}

// returns the Square of the ending position
public static Square findEnd(int[][] mat){
    for (int i=0;i<mat.length;i++){
        for(int j=0;j<mat[0].length;j++){
            if(mat[i][j] == 9)
                return new Square(i,j,0);
        }
    }
    return new Square(1,0);
}

/*
 In this method i tried to define which squares are to be deleted from the fullPath
 and return a new path with only the squares who are actually used in the shortest path.
 This method doesn't work for all examples it just works for some so i guess it is lacking.
 */
public static ArrayQueue<Square> correctPath(ArrayList<Square> path) throws QueueFullException {
    int i=0;
    while(i<path.size()-1){
        if (path.get(i).getdistance() == path.get(i+1).getdistance()){
            if (path.get(i+2)!=null && path.get(i-1)!=null && (!isNearSquare(path.get(i),path.get(i+2)) || !isNearSquare(path.get(i),path.get(i+2)))){
                path.remove(i);
            }
            else if (path.get(i+2)!=null && path.get(i-1)!=null && (!isNearSquare(path.get(i+1),path.get(i-1)) || !isNearSquare(path.get(i+1),path.get(i+2)))){
                path.remove(i+1);
            }
            else if (!isNearSquare(path.get(i),path.get(i+1))){
                path.remove(i);
            }
        }
        i++;
    }
    ArrayQueue<Square> correctPath = new ArrayQueue<>(path.size());
    while(i>=0){
        correctPath.enqueue(path.get(i));
        i--;
    }
    return correctPath;
}

static void printCorrectPath(ArrayQueue<Square> correctPath) throws QueueEmptyException {
    Square[] originalPath = new Square[correctPath.size()];
    for(int i=originalPath.length-1;i>=0;i--){
        originalPath[i] = correctPath.dequeue();
    }
    int i=0;
    while(i<originalPath.length-1){
        if(i == 0) System.out.println(originalPath[i]+" is the starting point.");
        System.out.println("From "+originalPath[i]+"to "+originalPath[i+1]);
        i++;
        if(i == originalPath.length-1) System.out.println(originalPath[i]+" is the ending point.");
    }
}

public static void searchPath(int[][] mat,Square start) throws QueueEmptyException,QueueFullException {
    //mat is the maze where 1 represents a wall,0 represent a valid square and 9 is the destination
    // When a square is visited from 0 it becomes a 2
    ROW=mat.length;
    COL=mat[0].length;
    Square dest = findEnd(mat);         // search for the number 9 and make a new Square and put it in dest
    int dist = BFS(mat,start,dest);   // find the least distance
    if (dist != Integer.MAX_VALUE)
        System.out.println("\nShortest Path is " + dist+" steps.");
    else
        System.out.println("Shortest Path doesn't exist");
}

// function to find the shortest path between a given source cell to a destination cell.
static int BFS(int[][] mat,Square src,Square dest) throws QueueFullException,QueueEmptyException {
    ArrayList<Square> fullPath = new ArrayList<>();                // path of all the squares checked
    boolean [][]visited = new boolean[ROW][COL];                   // if a square is visited then visited[x][y] = true
    ArrayQueue<Square> q = new ArrayQueue<>(mat.length*mat[0].length);      // Create a queue for BFS
    // check source and destination cell of the matrix have value 1
    if (mat[src.getY()][src.getX()] != 0 || mat[dest.getX()][dest.getY()] != 9) {
        return -1;
    }
    mat[src.getY()][src.getX()] = 2;                // Mark the source cell as visited
    visited[src.getX()][src.getY()] = true;
    q.enqueue(src);                                 // Enqueue source cell
    fullPath.add(src);                              // Add source to the full path
    while (!q.isEmpty())                            // Do a BFS starting from source cell
    {
        Square curr = q.front();
        if (curr.getX() == dest.getX() && curr.getY() == dest.getY()) {     // If we have reached the destination cell we are done
            printCorrectPath(correctPath(fullPath));
            return curr.getdistance();
        }
        q.dequeue();            // Otherwise dequeue the front cell in the queue and enqueue its adjacent cells
        for (int i = 0; i < 4; i++){
            int row = curr.getX() + rowNum[i];
            int col = curr.getY() + colNum[i];
            // if adjacent cell is valid,has path and not visited yet,enqueue it.
            if (isValid(row,col) && mat[row][col] == 0 || mat[row][col] == 9 && !visited[row][col]){
                mat[row][col] = 2;
                visited[row][col] = true;       // mark cell as visited and enqueue it
                Square Adjcell = new Square(row,col,curr.getdistance() + 1 );
                q.enqueue(Adjcell);
                fullPath.add(Adjcell);
            }
        }
    }
    return -1;       // Return -1 if destination cannot be reached
}

}

这是我进行测试的班级。

public class MazeRunner {

// Maze is a 2d array and it has to be filled with walls peripherally
// with walls so this algorithm can work. Our starting position in this
// will be (1,1) and our destination will be flagged with a 9 which in
// this occasion is (11,8).
private int[][] maze ;
private final List<Integer> path = new ArrayList<>();
public long startTime,stopTime;

public MazeRunner(int [][] maze){
    this.maze = maze;
}

public void runBFSAlgorithm(int startingX,int startingY) throws QueueEmptyException,QueueFullException {
    startTime = System.nanoTime();
    BreathAlgorithm.searchPath(maze,new Square(startingX,startingY,0));
    stopTime = System.nanoTime();
    System.out.printf("Time for Breath First Algorithm: %.5f milliseconds.\n",(stopTime-startTime)*10e-6);
}

public void printMaze(){
    for (int[] ints : maze) {
        for (int anInt : ints) {
            System.out.print(anInt + " ");
        }
        System.out.println();
    }
}

public static void main(String[] args) throws FileNotFoundException,QueueEmptyException,QueueFullException {
    int [][] maze = {{1,1},{1,9,1}};
    int[] startingPoint = {1,1};
    MazeRunner p = new MazeRunner(maze);
    p.printMaze();
    p.runBFSAlgorithm(startingPoint[0],startingPoint[1]);
}

}

我的处决看起来像这样:

The execution output

解决方法

赋予Square实例一个额外的属性:Square cameFrom;

然后在您的BFS中进行更改:

q.enqueue(Adjcell);

收件人:

Adjcell.cameFrom = curr;
q.enqueue(Adjcell);

然后,更改correctPath,使其以dest作为参数,并按照由ArrayList<Square>属性形成的链接列表,将路径构建为cameFrom

然后只需反转此列表即可以正确的顺序获取它。