@carabia

Как составить список пути используя алгоритм BFS?

Доброго времени суток!
Использую алгоритм поиска в ширину для определения кратчайшего пути в двумерном массиве. Работает корректно,
однако не могу получить путь, пройденный от источника к месту назначения в виде очереди или списка.

public class SearchMazeBFS {

    private static final int ROW = 9;
    private static final int COL = 10;
    private int[] rowNum = new int[] { -1, 0, 0, 1 };
    private int[] colNum = new int[] { 0, -1, 1, 0 };

    private static class Point {
        private Point(int row, int col) {
            this.x = row;
            this.y = col;
        }

        private int x;
        private int y;
    }

    private static class QueueNode {
        private QueueNode(Point src, int d) {
            this.pt = src;
            this.dist = d;
        }

        private Point pt;
        private int dist;
    }

    private boolean isValid(int row, int col) {
        return (((row >= 0) && (row < ROW)) && ((col >= 0) && (col < COL)));
    }

    private int BFS(int mat[][], Point src, Point dest) {
        if ((mat[src.x][src.y] == 0) || (mat[dest.x][dest.y] == 0))
            return Integer.MAX_VALUE;

        boolean[][] visited = new boolean[ROW][COL];

        visited[src.x][src.y] = true;

        Queue<QueueNode> q = new ArrayDeque<>();

        QueueNode s = new QueueNode(src, 0);
        q.add(s);

        while (!q.isEmpty()) {
            QueueNode curr = q.peek();
            Point pt = curr.pt;

            if (pt.x == dest.x && pt.y == dest.y) {
                return curr.dist;
            }

            q.poll();

            for (int i = 0; i < 4; i++) {
                int row = pt.x + rowNum[i];
                int col = pt.y + colNum[i];

                if ((isValid(row, col) && mat[row][col] == 1)
                        && !visited[row][col]) {
                    visited[row][col] = true;
                    QueueNode adjCell = new QueueNode(new Point(row, col),
                            curr.dist + 1);
                    q.add(adjCell);
                }
            }
        }

        return Integer.MAX_VALUE;
    }

    public static void main(String[] args) {
        SearchMazeBFS smbfs = new SearchMazeBFS();
        int[][] mat = new int[][] {
                { 1, 0, 1, 1, 1, 1, 0, 1, 1, 1 },
                { 1, 0, 1, 0, 1, 1, 1, 0, 1, 1 },
                { 1, 1, 1, 0, 1, 1, 0, 1, 0, 1 },
                { 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 },
                { 1, 1, 1, 0, 1, 1, 1, 0, 1, 0 },
                { 1, 0, 1, 1, 1, 1, 0, 1, 0, 0 },
                { 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
                { 1, 0, 1, 1, 1, 1, 0, 1, 1, 1 },
                { 1, 1, 0, 0, 0, 0, 1, 0, 0, 1 }
        };

        Point source = new SearchMazeBFS.Point(0, 2);
        Point dest = new SearchMazeBFS.Point(2, 0);

        int dist = smbfs.BFS(mat, source, dest);

        if (dist != Integer.MAX_VALUE)
            System.out.println("Shortest Path is " + dist);
        else
            System.out.println("Shortest Path doesn't exist");
    }
}
  • Вопрос задан
  • 335 просмотров
Пригласить эксперта
Ответы на вопрос 2
wataru
@wataru Куратор тега Алгоритмы
Разработчик на С++, экс-олимпиадник.
Надо для каждой вершины хранить предыдущую. Запишите это значение, когда кладете вершину в очередь. Для вершины (row, col) у вас в коде предыдущая (pt.x, pt.y).

После, когда нашли расстояние до конечной вершины можно создать массив этой длины и заполнить его с конца. Нужен указатель, который указывает на конечную вершину. Двигаете его в предыдущую для текущей вершины, пока не придете в начало или известное количество шагов (уже найденное расстояние).
Ответ написан
@Mercury13
Программист на «си с крестами» и не только
Вместо
boolean[][] visited = new boolean[ROW][COL];

надо сделать такое:
static final byte DIR_UNKNOWN = 0;
static final byte DIR_UP = 1;
...

byte[][] bestDirection = new boolean[ROW][COL];  // изначально заполнено DIR_UNKNOWN


for (int dir = DIR_UP; dir <= DIR_RIGHT; ++dir) {
  ...
  bestDirection[row][col] = dir;
}

Добравшись до финиша, делаем обратный ход. А именно: определяем, какой bestDirection у финиша, и если он, например, DIR_UP — смещаемся на 1 вниз. И так далее, пока не доберёмся до старта.

Если финишей много — возможно, лучше будет начинать с них, внеся их в очередь в случайном порядке. А потом, когда поиск доберётся до старта, сделать обратный ход.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
Bell Integrator Ульяновск
До 400 000 ₽
Bell Integrator Хабаровск
До 400 000 ₽
Bell Integrator Ижевск
До 400 000 ₽
19 апр. 2024, в 23:00
5000 руб./за проект
19 апр. 2024, в 20:43
20000 руб./за проект