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

2024-01-05

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

物体只能水平或垂直移动。

假设下面的示例是我正在查看的网格,它表示为二维矩阵。对象是 *,0 是对象可以移动到的空白空间,1 是对象无法跳过或继续的墙壁。

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

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

需要注意的是,计算中不考虑 * 的原始位置,这就是为什么在下面的示例中,消息将打印 9 而不是 10。

我有一个 isaWall 方法,可以告诉我单元格是否是墙。 isaWall 方法位于 Cell 类中。每个单元格都由其坐标表示。我研究过使用 BFS 或 DFS 等算法,但我不太明白在这种情况下如何实现它们,因为我对这些算法不太熟悉。我想过使用 Cells 作为图的节点,但不太确定如何遍历图,因为从我在网上看到的 BFS 和 DFS 的示例来看,通常会有一个目标节点和源节点(源是*) 的位置,但在这种情况下我实际上没有目标节点。我真的很感激一些帮助。

00111110
01000010
100*1100
10001000
11111000

编辑:我检查了评论中推荐的网站,并尝试实现我自己的版本。不幸的是它没有起作用。我知道我必须扩展“前沿”,我基本上只是将扩展代码翻译为Java,但它仍然不起作用。该网站继续解释该过程,但就我而言,没有可以转到的目标单元格。我真的很感激与我的案例有关的示例或更清晰的解释。

EDIT2:我仍然很困惑,有人可以帮忙吗?


虽然 BFS/DFS 常见used寻找起点和终点之间的联系,这实际上并不是它们的本质。 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, 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;
        }
    }
}

细胞.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;
    }
}

现在来编写我们的 DFS 函数。 DFS 递归地触及每个可到达的单元格once通过以下步骤:

  1. 将当前单元格标记为已访问
  2. 循环遍历每个相邻单元格
  3. 如果该单元格尚未被访问过,则对该单元格进行 DFS,并将与该单元格相邻的单元格数量添加到当前计数中
  4. 返回与当前单元格相邻的单元格数量 + 1

你可以看到这个的可视化here https://www.youtube.com/watch?v=tlPuVe5Otio。有了我们已经编写的所有辅助功能,这非常简单:

地图助手.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;
    }
}

就是这样!如果您需要有关代码的任何解释,请告诉我。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 BFS 查找网格上对象的可能路径数 的相关文章

  • Maven 未运行 Spring Boot 测试

    我有一个要测试的 Spring Boot REST API 我可以在 Eclipse 中手动运行测试 无需 Maven 并通过将应用程序作为 JUnit 测试运行 它运行良好并显示结果 但是mvn test正如您将在下面发现的那样 它不起作
  • cucumber.json 报告被重新运行场景报告覆盖

    我有一个具有相同技术堆栈 JAVA1 8 Cucumber JVM JUnit Maven 的 UI 测试项目和一个 API 测试项目 这两个项目都向我展示了这个问题 可能是因为两者都存在相同的依赖关系集 我使用了使用 maven sure
  • 使用 Firebase Java API 检索/格式化数据的最佳方式

    我在用着Firebase用于数据存储Android项目 并使用Firebase Java API来处理数据 不过 我不确定我是否尽可能高效地完成此操作 并且我希望获得一些有关检索和格式化数据的最佳实践的建议 我的Firebase存储库看起来
  • 用Java截取网页的屏幕截图[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 有没有一个免费的工具可以读取给定的网页并截取它的屏幕截图 我使用 VirtualFramebuffer 和 Firefox Binary
  • Vaadin框架播放视频

    我可以使用 Vaadin Framewotk 播放视频吗 主要思想是从本地驱动器加载 flv 或 avi 格式的视频文件 并使用 vaadin 框架在网络上播放 谢谢 Sampler中有一个示例 http demo vaadin com s
  • 为什么需要添加工件 JSR305 才能使用 Guava 14+?

    在stackoverflow上查找信息时 我看到了一个与我类似的问题 但没有真正的答案here https stackoverflow com questions 3800033 guava r07 gwt and javax annota
  • 如何在Eclipse中制作war文件[重复]

    这个问题在这里已经有答案了 制作war文件的简单方法是什么 当我右键单击 在服务器上运行 时 我的项目正在运行 但我想部署在 tomcat 服务器上 我已经安装了m2clipse但这给了我一个错误 maven是否必须制作war文件 我需要特
  • 规范路径和绝对路径有什么区别? [复制]

    这个问题在这里已经有答案了 可能的重复 Java 中的 getPath getAbsolutePath 和 getCanonicalPath 有什么区别 https stackoverflow com questions 1099300 w
  • 如何使用 Java2D 创建硬件加速图像?

    我正在尝试创建一个快速图像生成器 它可以执行大量 2d 转换和形状渲染 因此我尝试使用 BufferedImage 然后获取 Graphics2D 对象来执行所有绘图 我现在主要关心的是 make 速度非常快 所以我创建一个像这样的 Buf
  • 是否可以将 BitmapDescriptor 转换为 Bitmap?

    我需要将 BitmapDescriptor 转换为 Bitmap 我可以使用以下代码将位图转换为 BitmapDescriptor BitmapDescriptor bd BitmapDescriptorFactory fromBitmap
  • 在java中迭代日期

    我需要遍历一系列日期 不确定如何在 for 循环中获取第二天 我在用java util Date So plusDays 1 不能在 for 循环中用于获取下一个日期 Used date1 new Date date1 getTime 10
  • 使用 IntelliJ 调试 Java 进程 - 连接到套接字但不连接到目标 VM

    现在已解决 请参阅问题末尾 我正在尝试使用 IntelliJ Community Edition 的调试器来调试 Java 进程 套接字正在侦听 但是当我尝试连接时 调试过程显示以下内容 连接到目标虚拟机 地址 8003 传输 socket
  • java - IBM-IEEE 双精度浮点字节转换

    我需要在 Java 中对字节数组进行 IBM IEEE 浮点转换 我能够使用成功地进行单精度浮点字节的转换http www thecodingforums com threads c code for converting ibm 370
  • ImageIO read() 和 write() 操作后 GIF 图像变得错误

    我有这个代码 它只是读取 GIF 文件 用背景重新绘制它 然后输出到新的 GIF 文件 问题是结果文件变得奇怪 我不知道为什么它的质量变得很差 JPG 文件不会出现此问题 如何修复它 import java awt Color import
  • 通过命令行参数更改默认的 ant 目标

    最近我被分配了一个任务 让ant能够为不同的环境构建war包 除了一项功能外 我几乎完成了 蚂蚁接受一个env参数类似 Denv DEV 并使用不同的配置文件来制作war包 但默认目标是start它将构建 部署并启动 tomcat 我不希望
  • 使用相对于配置文件的路径引用 Spring 属性文件

    我正在将属性从 Spring 配置文件内部移动到单独的属性文件中 这包含在配置文件中
  • AWS Java SDK 中 DynamoDB v2 的迁移详细信息?

    有没有人对新的命名空间进行了更改 com amazonaws services dynamodbv2 以及 AWS Java SDK 1 4 2 及更高版本 中 DynamoDB 的接口 本地二级指数的发布显然需要根据1 4 2 发行说明
  • 术语“可序列化”是什么意思? [复制]

    这个问题在这里已经有答案了 不太确定我读过的定义可序列化实际上做了什么 import java io Serializable import java text StringCharacterIterator import java uti
  • Java中精确的时间测量

    Java 提供了两种获取当前时间的方法 System nanoTime and System currentTimeMillis 第一个给出的结果以纳秒为单位 但实际精度比这要差得多 许多微秒 JVM 是否已经为每台特定机器提供了最佳的价值
  • 获取给定字符串日期中该月的最后一天

    我的输入字符串日期如下 String date 1 13 2012 我得到的月份如下 SimpleDateFormat dateFormat new SimpleDateFormat MM dd yyyy Date convertedDat

随机推荐

  • Symfony 1.4 会话随机丢失

    这是我几个月前开始尝试的一个问题 从那以后我一直试图解决但没有成功 Symptoms symfony 在随机的时间间隔内丢失会话信息并注销用户 它似乎与网站的负载有某种联系 当负载较高时 用户注销似乎会更频繁 甚至可能会快至 30 秒 环境
  • 如何将 META 重新映射到 ALT?

    我在 Ubuntu 中使用 emacs 如何将 META 重新映射到 ALT 键 如果您在 gnome 终端中运行 emacs 则 gnome 终端可能会捕获您的 alt 键以打开 gui 菜单 文件 编辑等 您可以通过选择 编辑 gt g
  • Docker:服务器的空响应

    我在连接 docker 容器时遇到问题 服务器返回空响应 但配置似乎是正确的 当我使用 docker compose up 命令时 一切看起来都很好并且工作正常 但是我从服务器得到空响应 我仔细检查了端口映射 但我没有注意到任何东西 这是撰
  • git 不显示 unicode 文件名

    我在 Mac OS X 上使用 git 2 5 4 我的文件名包含 git 正在用转义符显示它 有没有办法让它使用unicode并显示字符 终端显然可以处理它 gt ls S l gt git status Untracked files
  • Discord.py重写获取公会成员列表

    只是想知道我将如何获取公会中所有当前成员的列表 然后将其作为消息返回 如果你想获取特定公会的成员数量 可以使用len guild members 如果您想获取列表 只需使用guild members 如果你想发送它 它可能不起作用 因为 D
  • Subversion - 是否可以禁用所有提交并使存储库只读?

    我有一个颠覆存储库 它是另一个远程存储库的镜像 我每周都会使用 svnsync 来镜像存储库 镜像存储库 本地副本 仅用于备份 我希望将镜像存储库保持为只读 即任何人都不能对此存储库提交任何更改 但他们可以使用它来读取源文件 因为它比远程存
  • 如何使用 mono 编译目录中的所有文件?

    我想用 mono 编译一个由多个文件组成的 C 应用程序 全部在 1 个目录中 我需要什么命令 Use gmcs out yourapp exe pkg dotnet cs or gmcs out yourapp exe pkg dotne
  • 从双精度数中删除 .0

    我正在尝试动态显示字符串中的数字 因此如果数字有小数 则显示它们 但如果没有 则不显示 0 示例 将 5 5 显示为 5 5 将 5 0 显示为 5 这是我到目前为止所拥有的 答案是双 double temp answer long tem
  • 如何在Python中进行指数和对数曲线拟合?我发现只有多项式拟合

    我有一组数据 我想比较哪一行最能描述它 不同阶的多项式 指数或对数 我使用 Python 和 Numpy 对于多项式拟合 有一个函数polyfit 但我没有发现这样的指数和对数拟合函数 有吗 或者另外如何解决 用于装配y A B log x
  • 显示模式对话框并获取结果

    我有一个静电WindowService帮助我创建新窗口和模式对话框的类 到目前为止 我所拥有的是这样的
  • 将 SQL Server 表加载到 pandas DataFrame 中的速度缓慢

    当使用 pyodbc 和主要函数 pandas read sql query pyodbc conn 从 SQL Server DB 加载超过 1000 万条记录时 Pandas 会变得异常缓慢 以下代码最多需要 40 45 分钟才能从 S
  • 将服务注入 Ember 对象 [不是 Ember 控制器]

    我正在尝试将 Ember 服务注入 Ember 对象 但不断收到以下错误 Assertion Failed Attempting to lookup an injected property on an object without a c
  • 想要在 iPhone 上显示 3D 模型:如何开始? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的
  • Postgres 将子查询结果括在括号中

    不要注意所提供的查询的无用性 它只是复杂查询的简化部分 我运行查询 SELECT elem FROM SELECT id FROM data AS elem 它产生的结果是 elem 5 4 24 3 23 为什么每个值都用括号括起来 所以
  • 没有依赖于模板参数的参数

    我正在尝试执行以下操作 template
  • 捕获所有键盘输入

    首先 我知道这可以用于键盘记录器 我不打算这样做 我正在寻找一个应用程序来侦听自定义按键组合 只是为了自动执行一些非常烦人的任务 有没有办法捕获键盘的所有输入 您似乎正在寻找RegisterHotKey http msdn microsof
  • 如何使用python脚本转换dos2unix csv文件

    我想在 Windows 中使用 python 将 csv 文件转换为 dos2unix 格式 现在我正在通过将 csv 文件放置在工作区 服务器 中并在 putty 中运行命令来手动执行操作 命令 dos2unix file receive
  • Compose UIBarButtonItem 在进入视图时会稍微改变位置

    当在导航栏中使用 UIBarButtonSystemItemCompose 按钮 呈现新视图时 位置会稍微偏离并在视图进入视图后进行调整 我认为这是iOS 使用8 3版本 中的一个错误 仅在使用 UIBarButtonSystemItemC
  • Puppet 6 和模块 puppetlabs/accounts 不会以 Hiera YAML 格式创建用户帐户

    当我跑步时puppet agent test我没有错误输出 但用户没有创建 我的木偶 hira yaml 配置是 version 5 datadir etc puppetlabs code environments data hash ya
  • 使用 BFS 查找网格上对象的可能路径数

    我有一个代表网格的矩阵 并且想找出对象可以移动到的所有可能的位置 物体只能水平或垂直移动 假设下面的示例是我正在查看的网格 它表示为二维矩阵 对象是 0 是对象可以移动到的空白空间 1 是对象无法跳过或继续的墙壁 如果该对象只能水平或垂直移