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
distance
array traverse to record the starting point and the distance,distance
the array is initialized to 0 from the starting point, the remaining points are initialized to the maximum value of intINT_MAXVALUE
. BFS then, with a queuequeue
record points traversed, and indistance
addition 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 isINT_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
distance
array, 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 indistance
a 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; } }