El uso de BFS para encontrar el número de caminos posibles para un objeto en una cuadrícula

MajesticButterfly:

Tengo una matriz que representa una rejilla y le gustaría averiguar todos los lugares posibles de un objeto se puede mover.

Un objeto sólo puede moverse horizontalmente o verticalmente.

Vamos a suponer que el siguiente ejemplo es la red que estoy viendo, que se representa como una matriz 2D. El objeto es el *, los 0s son espacios vacíos que un objeto puede mover a, y los 1s son muros que el objeto no puede saltar por encima o pasa al.

¿Cuál es la mejor manera de encontrar todos los movimientos posibles de este objeto, siempre que sólo puede moverse en horizontal o vertical?

Me gustaría presentar un mensaje diciendo: "Hay 9 lugares del objeto puede ir." La figura 9 es para el ejemplo siguiente, pero me gustaría que funcione para cualquier configuración de los siguientes cuadrícula. Así que todo lo que tengo que hacer es dar las coordenadas actuales del * y me van a dar el número de posiciones posibles que puede mover.

Una cosa a destacar es que la * 's posición original no se considera en los cálculos, por lo que para el ejemplo a continuación el mensaje imprimiría 9 y 10 no.

Tengo un método isaWall que me dice que si la célula es una pared o no. El método isaWall está en una clase de la célula. Cada célula está representado por sus coordenadas. Miré en el uso de algoritmos como BFS o DFS, pero yo no entendía muy bien cómo ponerlas en práctica en este caso, ya que no estoy muy familiarizado con los algoritmos. Pensé en el uso de las células como nodos de la gráfica, pero no estaba muy seguro de cómo atravesar el gráfico porque a partir de los ejemplos que he visto en línea de BFS y DFS, que normalmente tienen un nodo nodo de destino y la fuente (la fuente es el posición del *), pero en realidad no tienen un nodo de destino en este caso. Realmente agradecería un poco de ayuda.

00111110
01000010
100*1100
10001000
11111000

EDIT: he comprobado el sitio web que se recomienda en los comentarios y trató de poner en práctica mi propia versión. Lamentablemente no funcionó. Yo entiendo que tengo para expandir la "frontera" y que, básicamente, sólo traduje el código de expansión de Java, pero todavía no funciona. El sitio web continúa explicando el proceso, pero en mi caso, no hay una celda de destino a donde ir. Te lo agradecería un ejemplo o una explicación más clara referente a mi caso.

Edit2: Estoy todavía bastante confundido por ella, alguien puede ayudar por favor?

dominicm00:

Mientras BFS / DFS son comúnmente utilizados para encontrar las conexiones entre un punto de inicio y final, que no es realmente lo que son. BFS / DFS son "algoritmos gráfico de recorrido", que es una forma elegante de decir que se encuentran todos los puntos de acceso desde un punto de inicio. DFS (primera búsqueda en profundidad) es más fácil de implementar, por lo que vamos a utilizar para sus necesidades (nota: BFS se utiliza cuando es necesario encontrar lo lejos que cualquier punto es desde el punto de inicio, y DFS se utiliza cuando sólo se necesita para ir a cada punto).

No sé exactamente cómo está estructurado sus datos, pero voy a asumir su mapa es una matriz de enteros y definir algunas funciones básicas (por motivos de simplicidad hice la celda de inicio 2):

Map.java

import java.awt.*;

public class Map {
    public final int width;
    public final int height;

    private final Cell[][] cells;
    private final Move[] moves;
    private Point startPoint;

    public Map(int[][] mapData) {
        this.width = mapData[0].length;
        this.height = mapData.length;

        cells = new Cell[height][width];
        // define valid movements
        moves = new Move[]{
            new Move(1, 0),
            new Move(-1, 0),
            new Move(0, 1),
            new Move(0, -1)
        };

        generateCells(mapData);
    }

    public Point getStartPoint() {
        return startPoint;
    }

    public void setStartPoint(Point p) {
        if (!isValidLocation(p)) throw new IllegalArgumentException("Invalid point");

        startPoint.setLocation(p);
    }

    public Cell getStartCell() {
        return getCellAtPoint(getStartPoint());
    }

    public Cell getCellAtPoint(Point p) {
        if (!isValidLocation(p)) throw new IllegalArgumentException("Invalid point");

        return cells[p.y][p.x];
    }

    private void generateCells(int[][] mapData) {
        boolean foundStart = false;
        for (int i = 0; i < mapData.length; i++) {
            for (int j = 0; j < mapData[i].length; j++) {
                /*
                0 = empty space
                1 = wall
                2 = starting point
                 */
                if (mapData[i][j] == 2) {
                    if (foundStart) throw new IllegalArgumentException("Cannot have more than one start position");

                    foundStart = true;
                    startPoint = new Point(j, i);
                } else if (mapData[i][j] != 0 && mapData[i][j] != 1) {
                    throw new IllegalArgumentException("Map input data must contain only 0, 1, 2");
                }
                cells[i][j] = new Cell(j, i, mapData[i][j] == 1);
            }
        }

        if (!foundStart) throw new IllegalArgumentException("No start point in map data");
        // Add all cells adjacencies based on up, down, left, right movement
        generateAdj();
    }

    private void generateAdj() {
        for (int i = 0; i < cells.length; i++) {
            for (int j = 0; j < cells[i].length; j++) {
                for (Move move : moves) {
                    Point p2 = new Point(j + move.getX(), i + move.getY());
                    if (isValidLocation(p2)) {
                        cells[i][j].addAdjCell(cells[p2.y][p2.x]);
                    }
                }
            }
        }
    }

    private boolean isValidLocation(Point p) {
        if (p == null) throw new IllegalArgumentException("Point cannot be null");

        return (p.x >= 0 && p.y >= 0) && (p.y < cells.length && p.x < cells[p.y].length);
    }

    private class Move {
        private int x;
        private int y;

        public Move(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }
    }
}

Cell.java

import java.util.LinkedList;

public class Cell {
    public final int x;
    public final int y;
    public final boolean isWall;
    private final LinkedList<Cell> adjCells;

    public Cell(int x, int y, boolean isWall) {
        if (x < 0 || y < 0) throw new IllegalArgumentException("x, y must be greater than 0");

        this.x = x;
        this.y = y;
        this.isWall = isWall;

        adjCells = new LinkedList<>();
    }

    public void addAdjCell(Cell c) {
        if (c == null) throw new IllegalArgumentException("Cell cannot be null");

        adjCells.add(c);
    }

    public LinkedList<Cell> getAdjCells() {
        return adjCells;
    }
}

Ahora escribir nuestra función DFS. Un DFS toca de forma recursiva cada célula puede llegar una vez con los siguientes pasos:

  1. celda actual Marcar como visitado
  2. Loop a través de cada célula adyacente
  3. Si la célula ya no ha sido visitado, DFS que la célula, y añadir el número de celdas adyacentes a la celda a la cifra actual
  4. Devuelve el número de celdas adyacentes a la celda actual + 1

Se puede ver una visualización de este aquí . Con todas las funciones del ayudante que ya escribimos, esto es bastante simple:

MapHelper.java

class MapHelper {
    public static int countReachableCells(Map map) {
        if (map == null) throw new IllegalArgumentException("Arguments cannot be null");
        boolean[][] visited = new boolean[map.height][map.width];

        // subtract one to exclude starting point
        return dfs(map.getStartCell(), visited) - 1;
    }

    private static int dfs(Cell currentCell, boolean[][] visited) {
        visited[currentCell.y][currentCell.x] = true;
        int touchedCells = 0;

        for (Cell adjCell : currentCell.getAdjCells()) {
            if (!adjCell.isWall && !visited[adjCell.y][adjCell.x]) {
                touchedCells += dfs(adjCell, visited);
            }
        }

        return ++touchedCells;
    }
}

¡Y eso es! Que me haga saber si necesita ninguna explicación sobre el código.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=210953&siteId=1
Recomendado
Clasificación