Summary of maze algorithm (shortest path)

Algorithm summary of maze algorithm (shortest path)

@author:Jingdai
@date:2020.11.20

The maze problem is a very classic algorithm problem, now I will summarize it.

Title description

Give you a maze, and give you a starting point and ending point. Please give the shortest path from the starting point to the end point. If there is no shortest path, output -1. Maze with '#'representatives of obstacles remaining characters can go.

Enter the description. The two numbers in the first line represent the size of the maze (the number of rows m and the number of columns n); the second line represents the coordinates of the starting point and the end point; the next m line is the maze.

  • Input example:

    10 10
    0 1 9 8
    #S######.#
    ......#..#
    .#.##.##.#
    .#........
    ##.##.####
    ....#....#
    .#######.#
    ....#.....
    .####.###.
    ....#...G#
    
  • Sample output:

    22
    

Ideas

For the maze problem, you can use dfs or bfs, but the title requires the shortest path. If you use dfs, you need to traverse all situations. When you find a path, you can’t return directly. You need to record the current path and continue to find the next path. Then calculate the shortest path from all the paths. It can be seen that dfs is more troublesome to calculate the shortest path, so bfs is used here.

Using one distancearray traverse to record the starting point and the distance, distancethe array is initialized to 0 from the starting point, the remaining points are initialized to the maximum value of int INT_MAXVALUE. BFS then, with a queue queuerecord points traversed, and in distanceaddition to its value as a previous point in the note value.

During the traversal process, in addition to the obstacle points cannot be walked, the traversed points cannot be walked (traversal indicates that there was a shorter path to this point before, so it must not be the shortest path now). So how to judge whether it has been traversed? It is very simple. At the beginning, we initialized to INT_MAXVALUE, if its value is INT_MAXVALUE, it means it has not been traversed, otherwise it means it has been traversed. When the traversal reaches the end, the representative finds it and returns directly. If the end cannot be reached at the end of the traversal, it means it is unreachable, and -1 is returned.

Below is the code.

import java.util.*;

public class Solution {
     
     

    public static void main(String[] args) {
     
     

        Scanner scanner = new Scanner(System.in);
        
        int row;
        int column;
        row = scanner.nextInt();
        column = scanner.nextInt();
        scanner.nextLine();

        int[] start = new int[2];
        int[] end = new int[2];
        start[0] = scanner.nextInt();
        start[1] = scanner.nextInt();
        end[0] = scanner.nextInt();
        end[1] = scanner.nextInt();
        scanner.nextLine();

        char[][] maze = new char[row][column];
        for (int i = 0; i < row; i++) {
     
     
            String curRow = scanner.nextLine();
            maze[i] = curRow.toCharArray();
        }
        System.out.println(bfsPath(maze, start, end));
        
    }

    public static int bfsPath(char[][] maze, int[] start, int[] end) {
     
     
        
        int row = maze.length;
        int column = maze[0].length;

        int[][] distance = new int[row][column];
        for (int i = 0; i < row; i++) {
     
     
            Arrays.fill(distance[i], Integer.MAX_VALUE);
        }

        int[][] direction = {
     
     {
     
     0, 1}, {
     
     1, 0}, {
     
     0, -1}, {
     
     -1, 0}};

        // initiate
        LinkedList<int[]> queue = new LinkedList<>();
        queue.offer(start);
        distance[start[0]][start[1]] = 0;

        boolean isFound = false;
        while (queue.size() != 0) {
     
     
            int[] pre = queue.poll();
            for (int i = 0; i < 4; i++) {
     
     
                int[] cur = {
     
     pre[0] + direction[i][0], pre[1] + direction[i][1]};
                if (cur[0] >= 0 && cur[0] < row
                        && cur[1] >= 0 && cur[1] < column
                        && maze[cur[0]][cur[1]] != '#'
                        && distance[cur[0]][cur[1]] == Integer.MAX_VALUE) {
     
      // can go
                    distance[cur[0]][cur[1]] = distance[pre[0]][pre[1]] + 1;
                    if (cur[0] == end[0] && cur[1] == end[1]) {
     
      // find
                        isFound = true;
                        break;
                    }
                    queue.offer(cur);
                }
            }
            if (isFound) {
     
     
                break;
            }
        }

        return distance[end[0]][end[1]] == Integer.MAX_VALUE 
            ? -1 : distance[end[0]][end[1]];
    }

}

Only the length of the shortest path is output here. What if the topic is to find the specific shortest path? In fact, very easy to take advantage of our previous distancearray, beginning from the end, looking back. If point a is a point in the path, which one is the previous point? It is around those points in distancea distance equal to that point it minus 1, according to this you can find the path back step by step. Because it is in reverse order, here we use the last-in, first-out nature of the stack to complete the positive order output of the path. The code is as follows.

import java.util.*;

public class Solution {
     
     

    public static int[][] distance;
    public static int row;
    public static int column;

    public static void main(String[] args) {
     
     

        Scanner scanner = new Scanner(System.in);
        
        row = scanner.nextInt();
        column = scanner.nextInt();
        scanner.nextLine();

        int[] start = new int[2];
        int[] end = new int[2];
        start[0] = scanner.nextInt();
        start[1] = scanner.nextInt();
        end[0] = scanner.nextInt();
        end[1] = scanner.nextInt();
        scanner.nextLine();

        char[][] maze = new char[row][column];
        for (int i = 0; i < row; i++) {
     
     
            String curRow = scanner.nextLine();
            maze[i] = curRow.toCharArray();
        }

        distance = new int[row][column];
        for (int i = 0; i < row; i++) {
     
     
            Arrays.fill(distance[i], Integer.MAX_VALUE);
        }

        int pathLength = bfsPath(maze, start, end);
        System.out.println(pathLength);


        LinkedList<int[]> path = null;
        
        if (pathLength != -1) {
     
     
            path = generatePath(start, end);
            for (int[] step : path) {
     
     
                System.out.println(Arrays.toString(step));
            }
        }
    }

    public static int bfsPath(char[][] maze, int[] start, int[] end) {
     
     
        
        int row = maze.length;
        int column = maze[0].length;

        int[][] direction = {
     
     {
     
     0, 1}, {
     
     1, 0}, {
     
     0, -1}, {
     
     -1, 0}};

        // initiate
        LinkedList<int[]> queue = new LinkedList<>();
        queue.offer(start);
        distance[start[0]][start[1]] = 0;

        boolean isFound = false;
        while (queue.size() != 0) {
     
     
            int[] pre = queue.poll();
            for (int i = 0; i < 4; i++) {
     
     
                int[] cur = {
     
     pre[0] + direction[i][0], pre[1] + direction[i][1]};
                if (cur[0] >= 0 && cur[0] < row
                        && cur[1] >= 0 && cur[1] < column
                        && maze[cur[0]][cur[1]] != '#'
                        && distance[cur[0]][cur[1]] == Integer.MAX_VALUE) {
     
      // can go
                    distance[cur[0]][cur[1]] = distance[pre[0]][pre[1]] + 1;
                    if (cur[0] == end[0] && cur[1] == end[1]) {
     
      // find
                        isFound = true;
                        break;
                    }
                    queue.offer(cur);
                }
            }
            if (isFound) {
     
     
                break;
            }
        }

        return distance[end[0]][end[1]] == Integer.MAX_VALUE 
            ? -1 : distance[end[0]][end[1]];
    }

    public static LinkedList<int[]> generatePath(int[] start, int[] end) {
     
     
        
        LinkedList<int[]> path = new LinkedList<>();
        
        int[] cur = new int[]{
     
     end[0], end[1]};
        int[][] direction = {
     
     {
     
     0, 1}, {
     
     1, 0}, {
     
     0, -1}, {
     
     -1, 0}};
        while (true) {
     
     
            path.push(cur);
            if (cur[0] == start[0] 
                    && cur[1] == start[1]) {
     
     
                break;
            }

            for (int i = 0; i < 4; i++) {
     
     
                if (cur[0] + direction[i][0] >= 0 && cur[0] + direction[i][0] < row
                    && cur[1]+direction[i][1] >= 0 && cur[1]+direction[i][1] < column) {
     
     
                    if (distance[cur[0] + direction[i][0]][cur[1] + direction[i][1]] 
                        == distance[cur[0]][cur[1]] - 1) {
     
     
                        cur = new int[]{
     
     cur[0] + direction[i][0], cur[1] + direction[i][1]};
                        break;
                    }
                }
            }
        }
        return path;
    }

}      

Guess you like

Origin blog.csdn.net/qq_41512783/article/details/109839709
Recommended