迷路アルゴリズムの概要(最短経路)

迷路アルゴリズムのアルゴリズム概要(最短経路)

@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;
    }

}      

おすすめ

転載: blog.csdn.net/qq_41512783/article/details/109839709