加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java-使用BFS查找网格上对象的可能路径数

发布时间:2020-12-14 19:26:03 所属栏目:Java 来源:网络整理
导读:我有一个表示网格的矩阵,想找出对象可以移动到的所有可能位置. 一个对象只能水平或垂直移动. 假设下面的示例是我正在查看的网格,它表示为2d矩阵.对象是*,0是对象可以移动到的空白空间,1是对象不能跳过或继续前进的墙壁. 如果该对象只能水平或垂直移动,那么找

我有一个表示网格的矩阵,想找出对象可以移动到的所有可能位置.

一个对象只能水平或垂直移动.

假设下面的示例是我正在查看的网格,它表示为2d矩阵.对象是*,0是对象可以移动到的空白空间,1是对象不能跳过或继续前进的墙壁.

如果该对象只能水平或垂直移动,那么找到所有可能运动的最佳方法是什么?

我想打印一条消息,说:“该对象可以去9个地方.” 9是下面的示例,但是我希望它适用于以下网格的任何配置.所以我要做的就是给出*的当前坐标,这将给我它可以移动到的可能位置的数量.

需要注意的是,在计算中未考虑*的原始位置,因此对于下面的示例,该消息将显示9而不是10.

我有一个isaWall方法,可以告诉我该单元格是否为墙. isaWall方法在Cell类中.每个像元均由其坐标表示.我研究过使用BFS或DFS之类的算法,但是由于我不太熟悉算法,因此我不太了解如何在这种情况下实现它们.我曾考虑将Cells用作图的节点,但并不确定如何遍历图,因为从我在BFS和DFS网上看到的示例中,通常会有一个目标节点和源节点(源是*)的位置,但是在这种情况下,我实际上没有目的地节点.我真的很感谢您的帮助.

00222220
01000010
100*1100
10001000
22222000

编辑:我检查了评论中推荐的网站,并尝试实现自己的版本.不幸的是,它没有用.我知道我必须扩展“边界”,并且我基本上只是将扩展代码翻译成Java,但仍然无法正常工作.该网站继续说明该过程,但就我而言,没有目标单元格可访问.我真的很感谢与我的案子有关的示例或更清晰的解释.

EDIT2:我还是很困惑,有人可以帮忙吗?

最佳答案
虽然BFS / DFS通常用于查找起点和终点之间的连接,但实际上并非如此. BFS / DFS是“图形遍历算法”,这是一种花哨的说法,可以说它们发现了从起点可到达的每个点. DFS(深度优先搜索)更易于实现,因此我们将根据您的需要使用它(注意:当您需要查找到起点的任何距离时,都将使用BFS;仅在需要时才使用DFS.去每一点).

我不知道您的数据的确切结构,但是我假设您的地图是一个整数数组,并定义了一些基本功能(为简单起见,我将第一个单元格设置为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,new Move(0,1),-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;
        }
    }
}

单元格

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

现在编写我们的DFS函数. DFS通过以下步骤递归地触摸每个可达单元一次:

>将当前单元格标记为已访问
>遍历每个相邻的单元格
>如果尚未访问该单元格,请DFS该单元格,并将与该单元格相邻的单元格数量添加到当前计数中
>返回与当前单元格1相邻的单元格数

您可以看到此here的可视化.使用我们已经编写的所有帮助程序功能,这非常简单:

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

就是这样!让我知道您是否需要有关代码的任何说明.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读