迷路アルゴリズムのアルゴリズム概要(最短経路)
@author:Jingdai
@date:2020.11.20
迷路の問題は非常に古典的なアルゴリズムの問題です。ここで要約します。
タイトル説明
迷路を与え、始点と終点を与えます。始点から終点までの最短経路を与えてください。最短経路がない場合は、-1を出力します。
'#'
残りのキャラクターが行くことができる障害物の代表と迷路。説明を入力します。最初の行の2つの数字は迷路のサイズ(行数mと列数n)を表し、2番目の行は開始点と終了点の座標を表します。次のm行は迷路。
入力例:
10 10 0 1 9 8 #S######.# ......#..# .#.##.##.# .#........ ##.##.#### ....#....# .#######.# ....#..... .####.###. ....#...G#
サンプル出力:
22
アイデア
迷路問題の場合、dfsまたはbfsを使用できますが、タイトルには最短パスが必要です。dfsを使用する場合は、すべての状況をトラバースする必要があります。パスを見つけた場合、直接戻ることはできません。記録する必要があります。現在のパスを探し続け、次のパスを探し続けます。次に、すべてのパスから最短パスを計算します。dfsは最短パスを計算するのが面倒なので、ここではbfsを使用します。
1つの
distance
配列トラバースを使用して開始点と距離を記録すると、distance
配列は開始点から0に初期化され、残りの点はintの最大値に初期化されINT_MAXVALUE
ます。次に、BFSは、キューqueue
レコードポイントをトラバースし、distance
その値に加えて、音価の前のポイントとして使用します。トラバーサルプロセス中は、障害物ポイントを歩くことができないことに加えて、トラバースポイントを歩くこともできません(トラバーサルは、以前はこのポイントまでのパスが短かったことを示しているため、現在は最短パスであってはなりません)。では、トラバースされたかどうかを判断する方法は?非常に簡単です。最初に、
INT_MAXVALUE
値がの場合はINT_MAXVALUE
トラバースされていないことを意味し、そうでない場合はトラバースされたことを意味するように初期化しました。トラバーサルが終了すると、担当者はそれを見つけて直接戻ります。トラバーサルの終了時に終了に到達できない場合は、到達不能であることを意味し、-1を返します。以下はコードです。
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]]; } }
最短パスの長さのみがここに出力されます。トピックが特定の最短パスを見つけることである場合はどうなりますか?実際、前の
distance
配列を最後から振り返って利用するのは非常に簡単です。ポイントaがパス内のポイントである場合、前のポイントはどれですか?それは、そのポイントdistance
から1を引いたものに等しい距離にあるそれらのポイントの周りにあります。これによると、ステップごとに戻るパスを見つけることができます。逆順であるため、ここでは後入れ先出しのスタックの性質を使用して、パスの正の順序の出力を完了します。コードは次のとおりです。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; } }