Java 中的递归回溯解决填字游戏

2024-04-29

我需要在给定初始网格和单词的情况下解决填字游戏(单词可以多次使用或根本不使用).

初始网格如下所示:

++_+++
+____+
___+__
+_++_+
+____+
++_+++

这是一个单词列表示例:

pain
nice
pal
id

任务是填充占位符(水平或垂直长度 > 1)像那样:

++p+++
+pain+
pal+id
+i++c+
+nice+
++d+++

任何正确的解都是可以接受的,并且保证有解。


为了开始解决问题,我将网格存储为 2-dim。 char 数组,我按单词的长度将单词存储在集合列表中:List<Set<String>> words,因此例如长度为 4 的字可以通过以下方式访问words.get(4)

然后我从网格中提取所有占位符的位置并将它们添加到占位符列表(堆栈)中:

class Placeholder {
    int x, y; //coordinates 
    int l; // the length
    boolean h; //horizontal or not
    public Placeholder(int x, int y, int l, boolean h) {
        this.x = x;
        this.y = y;
        this.l = l;
        this.h = h;
    }
}

该算法的主要部分是solve() method:

char[][] solve (char[][] c, Stack<Placeholder> placeholders) {
    if (placeholders.isEmpty())
        return c;

    Placeholder pl = placeholders.pop();
    for (String word : words.get(pl.l)) {
        char[][] possibleC = fill(c, word, pl); // description below
        if (possibleC != null) {
            char[][] ret = solve(possibleC, placeholders);
            if (ret != null)
                return ret;
        }
    }
    return null;
}

功能fill(c, word, pl)仅返回一个新的填字游戏,其中当前单词写在当前占位符上pl. If word不兼容pl,则函数返回 null。

char[][] fill (char[][] c, String word, Placeholder pl) {

    if (pl.h) {
        for (int i = pl.x; i < pl.x + pl.l; i++)
            if (c[pl.y][i] != '_' && c[pl.y][i] != word.charAt(i - pl.x))
                return null;
        for (int i = pl.x; i < pl.x + pl.l; i++)
            c[pl.y][i] = word.charAt(i - pl.x);
        return c;

    } else {
        for (int i = pl.y; i < pl.y + pl.l; i++)
            if (c[i][pl.x] != '_' && c[i][pl.x] != word.charAt(i - pl.y))
                return null;
        for (int i = pl.y; i < pl.y + pl.l; i++)
            c[i][pl.x] = word.charAt(i - pl.y);
        return c;
    }
}

这是完整的代码雷克斯特 http://rextester.com/MEYRW1661.


问题是我的回溯算法不能很好地工作。假设这是我的初始网格:

++++++
+____+
++++_+
++++_+
++++_+
++++++

这是单词列表:

pain
nice

我的算法会把这个词pain垂直,但当意识到这是一个错误的选择时,它会回溯,但到那时初始网格将已经更改并且占位符的数量将减少。您认为如何修复该算法?


这可以通过两种方式解决:

  • Create 深拷贝 https://stackoverflow.com/questions/1564832/how-do-i-do-a-deep-copy-of-a-2d-array-in-java矩阵的开头fill,修改并返回(保持原始状态不变)。

    鉴于您已经传递了矩阵,因此不需要任何其他更改。

    这很简单,但效率相当低,因为每次尝试填写单词时都需要复制矩阵。

  • 创建一个unfill方法,它会恢复所做的更改fill,在每次 for 循环迭代结束时调用。

    for (String word : words.get(pl.l)) {
        if (fill(c, word, pl)) {
            ...
            unfill(c, word, pl);
        }
    }
    

    注:我改变了fill按照我下面的注释。

    当然,仅仅尝试擦除所有字母可能会擦除其他放置单词的字母。为了解决这个问题,我们可以统计每个字母包含多少个单词。

    更具体地说,有一个int[][] counts(也需要传递或以其他方式访问)以及每当您更新时c[x][y],也增加counts[x][y]。要恢复展示位置,请将该展示位置中每个字母的计数减 1,并且仅删除计数为 0 的字母。

    这有点复杂,但比上面的方法更有效。

    就代码而言,您可以将类似的内容放入fill:
    (第一部分,第二部分类似)

    for (int i = pl.x; i < pl.x + pl.l; i++)
        counts[pl.y][i]++;
    

    And unfill看起来像这样:(同样只是第一部分)

    for (int i = pl.x; i < pl.x + pl.l; i++)
        counts[pl.y][i]--;
    for (int i = pl.x; i < pl.x + pl.l; i++)
        if (counts[pl.y][i] == 0)
            c[pl.y][i] = '_';
    // can also just use a single loop with "if (--counts[pl.y][i] == 0)"
    

请注意,如果采用上面的第二种方法,那么简单地使用可能更有意义fill返回一个boolean (true如果成功)并通过c直到递归调用solve. unfill可以返回void,因为它不会失败,除非你有错误。

您在代码中传递的只有一个数组,您所做的只是更改其名称。

也可以看看Java是“按引用传递”还是“按值传递”? https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value

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

Java 中的递归回溯解决填字游戏 的相关文章

  • Java 中的 <-- 是什么? [复制]

    这个问题在这里已经有答案了 我遇到了下面的片段 它输出到4 3 2 1 我从来没有遇到过 lt 在爪哇 Is lt 使 var1 的值变为 var2 的运算符 public class Test public static void mai
  • 以相反的顺序打印任何集合中的项目?

    我在 使用 Java 进行数据结构和问题解决 一书中遇到以下问题 编写一个例程 使用 Collections API 以相反的顺序打印任何 Collection 中的项目 不要使用 ListIterator 我不会把它放在这里 因为我想让有
  • 时间复杂度和运行时间有什么区别?

    时间复杂度和运行时间有什么区别 它们是一样的吗 运行时间是指程序运行所需的时间 时间复杂度是对输入大小趋于无穷大时运行时间渐进行为的描述 您可以说运行时间 是 O n 2 或其他什么 因为这是描述复杂性类和大 O 表示法的惯用方式 事实上
  • 自定义列表字段点击事件

    我正在编写一个应用程序 其中我创建了用于显示列表视图的自定义列表字段 我的 CustomListField 包含连续的一个图像和文本 我正在通过单击列表字段行获取字段更改侦听器 但我也想将字段更改侦听器放在图像上 谁能告诉我我该怎么做 这是
  • 为什么用scala写的代码比用java写的慢6倍?

    我不确定我在编写 scala 代码时是否犯了一些错误 问题是 The four adjacent digits in the 1000 digit number that have the greatest product are 9 9
  • Java中Gson、JsonElement、String比较

    好吧 我想知道这可能非常简单和愚蠢 但在与这种情况作斗争一段时间后 我不知道发生了什么 我正在使用 Gson 来处理一些 JSON 元素 在我的代码中的某个位置 我将 JsonObject 的 JsonElements 之一作为字符串获取
  • java中如何知道一条sql语句是否执行了?

    我想知道这个删除语句是否真的删除了一些东西 下面的代码总是执行 else 是否删除了某些内容 执行此操作的正确方法是什么 public Deleter String pname String pword try PreparedStatem
  • 使用 OkHttp 下载损坏的文件

    我编写的下载文件的方法总是会产生损坏的文件 public static String okDownloadToFileSync final String link final String fileName final boolean te
  • JAXB - 忽略元素

    有什么方法可以忽略 Jaxb 解析中的元素吗 我有一个很大的 XML 文件 如果我可以忽略其中一个大而复杂的元素 那么它的解析速度可能会快很多 如果它根本无法验证元素内容并解析文档的其余部分 即使该元素不正确 那就更好了 例如 这应该只生成
  • 如何使用双重调度来分析图形基元的交集?

    我正在分析图形基元 矩形 直线 圆形等 的交互并计算重叠 相对方向 合并等 这被引用为双重调度的一个主要示例 例如维基百科 http en wikipedia org wiki Double dispatch 自适应碰撞算法通常要求 不同的
  • 如何在 IntelliJ IDEA 中运行 akka actor

    来自 Akka 网站文档 然后 这个主要方法将创建所需的基础设施 运行演员 启动给定的主要演员并安排 一旦主要参与者终止 整个应用程序就会关闭 因此 您将能够使用类似于以下的命令运行上面的代码 下列的 java classpath akka
  • 如何自定义舍入形式

    我的问题可能看起来很简单 但仍然无法得到有效的东西 我需要自定义 Math round 舍入格式或其他格式以使其工作如下 如果数字是 1 6 他应该四舍五入到 1 如果大于或等于 1 7 他应该四舍五入到 2 0 对于所有其他带有 6 的小
  • UseCompressedOops JVM 标志有什么作用以及何时应该使用它?

    HotSpot JVM 标志是什么 XX UseCompressedOops我应该做什么以及什么时候使用它 在 64 位 Java 实例上使用它 与不使用它 时 我会看到什么样的性能和内存使用差异 去年大多数 HotSpot JVM 都默认
  • Android - 存储对ApplicationContext的引用

    我有一个静态 Preferences 类 其中包含一些应用程序首选项和类似的内容 可以在那里存储对 ApplicationContext 的引用吗 我需要该引用 以便我可以在不继承 Activity 的类中获取缓存文件夹和类似内容 你使用的
  • titledBorder 标题中的图标

    您好 是否可以在 titledBorder 的标题中放置一个图标 例如以下代码 import java awt GridLayout import javax swing JFrame import javax swing JLabel i
  • Java 中清除嵌套 Map 的好方法

    public class MyCache AbstractMap
  • 带 getClassLoader 和不带 getClassLoader 的 getResourceAsStream 有什么区别?

    我想知道以下两者之间的区别 MyClass class getClassLoader getResourceAsStream path to my properties and MyClass class getResourceAsStre
  • 什么是 Java2D 处理程序线程?

    我创建了一个使用 Hibernate 的示例 java 应用程序 当我进行线程转储时 我观察到一个名为 Java2D Disposer 的奇怪线程 有人能告诉我该线程的功能吗 AWT 系统中的某些实体需要最终确定以释放资源 最突出的例子是j
  • 使用 DBCP 配置 Tomcat

    在闲置一段时间 几个小时 后 我们收到了 CommunicationsException 来自 DBCP 错误消息 在异常中 位于这个问题的末尾 但我没有看到任何配置文件中定义的 wait timeout 我们应该看哪里 在 tomcat
  • 关闭扫描仪是否会影响性能

    我正在解决一个竞争问题 在问题中 我正在使用扫描仪获取用户输入 这是 2 个代码段 一个关闭扫描器 一个不关闭扫描器 关闭扫描仪 import java util Scanner public class JImSelection publ

随机推荐

  • 如何解决错误“AttributeError:‘SparkSession’对象没有属性‘序列化器’?

    我正在使用 pyspark 数据框 我有一些代码试图在其中转换dataframe to an rdd 但我收到以下错误 AttributeError SparkSession 对象没有属性 序列化器 可能是什么问题 training tes
  • Python - 套接字错误,地址正在使用

    我目前正在尝试在 Xubuntu 12 10 x64 上设置 SiriServer 这不是重点 当我运行服务器时 python 返回错误 socket error Errno 98 Address already in use 默认情况下
  • 对嵌套的 observable 进行排序

    我这里有一个 JSON 文件 如下所示 question What is your age range options 10 20 20 30 30 40 40 50 question How did you find us options
  • TFS 2017 - 构建服务器不构建 Visual Studio 2017

    上周在我的构建服务器上升级 Visual Studio 2017 后 MS Build 15 0 不再使用 因此 每当我尝试编译使用新功能的 Visual Studio 2017 项目时 它们都会失败 构建日志中的警告是 找不到 Visua
  • 使用 jQuery 删除 元素?

    我不想使用 style css 中的样式 因此我决定从 DOM 中删除 style css 这在 Firefox 和 IE8 中工作正常 但在 IE6 中不行 LINK href http www example com style css
  • 分配字节数组时出现奇怪的错误

    byte frame to send new byte 6 code frame to send 0x68 0x04 0x83 0x00 0x00 0x00 Array edit Error 无效的表达式术语 预期的 您只能在构造时初始化时
  • Git GUI 推送到特定分支

    我如何使用 GIT gui 推送到远程的特定分支 我似乎找不到它的选择 假设我想推送到特定的分支名称 branchOne 怎么可能呢 我正在推动 gitlab 每当您将某些内容推送到远程服务器时 您都在推送特定的分支 在您的情况下 您有一个
  • 如何使用 Python 的 __import__ 函数执行相当于“从模块导入 *”的操作?

    给定一个带有模块名称的字符串 如何导入模块中的所有内容 就好像您调用了 from module import 即给定字符串 S module 如何获得与以下内容等效的内容 import S fromlist 这似乎没有按预期执行 因为它没有
  • 从浏览器使用 node.js 的文件系统功能

    我想创建一个从服务器中删除文件的函数 我打算使用此功能将设置 即数据库文件 恢复到默认状态 我使用以下命令运行我的服务器 node server js 我知道node js的文件系统 https nodejs org api fs html
  • 在类 Illuminate\Support\Facades\Schema 中找不到方法“create”

    我使用的是 Laravel 5 3 在 PhpStorm 中 create 方法和许多其他方法下有错误 我尝试了所有 ide helpers 但没有解决问题 有没有办法解决这个问题和自动完成 我发现问题的答案在于使用行 use Illumi
  • Eclipse Faces 配置编辑器不工作

    Summary 编辑 faces config xml 时 Eclipse 中的 Faces 配置编辑器不会打开 这是一个 JavaServer Faces 项目 Details 日食3 7 2 Eclipse m2e 1 0 1 m2e
  • 从哈希表中删除一个值的成本是多少?

    现在我有一个问题 当我们在插入过程中使用线性探测时 有人问我从哈希表中删除值的成本 通过阅读互联网上的各种内容 我发现它必须与负载因子有关 虽然我不确定 但我读到了负载因数与所需探头数量之间的关系 探头数量 1 1 LF 所以我相信成本必须
  • 特殊字符无法正确显示

    In a TextArea 我正在使用 字符 但无法正确显示 相反 它显示的是这样的 我如何获得 字符才能正常显示 您可能没有使用 Ascii 撇号 而是使用一些非 Ascii 标点符号 例如正确的标点撇号 出现问题的原因是您的 HTML
  • Java中printf左对齐

    当我运行该程序时 阶乘值右对齐 有没有办法让它左对齐 同时保持中间 50 个空格 public class Exercise 5 13 public static void main String args int numbers 1 2
  • 应该如何在 Ant Design Upload 组件中设置 customRequest 以使用 XMLHttpRequest?

    我的组件一团糟 现在我传递了一个函数 我已经尝试了一百万件事但无法让它工作 export default class DatafileUpload extends Component initialState fileUploading f
  • Datalogic得利捷 Falcon X3 - 条码扫描器

    我刚刚拿到 Datalogic Falcon X3 条码设备 有人问我是否可以制作一个 javascript 应用程序来读取条码并通过 sql 将其发送到数据库 由于我不太喜欢 C C 和 Visual Studio 2008 中的 Win
  • 如何始终显示滚动条?

    如何在 UWP 应用中始终显示滚动条 滚动条总是在几秒钟后消失 我尝试过设置ScrollViewer VerticalScrollBarVisibility Visible 但滚动条仍然消失 我已经看过了Xaml UI 基础示例 https
  • CURL 静态链接未解析的外部符号

    我在 x64 Native Tools 命令提示符 Visual Studio 中使用此命令从源代码构建了 CURL 静态库 nmake f Makefile vc 模式 静态机器 AMD64 我将 lib 文件夹添加到链接器库文件夹 将
  • 从数据框 R 列表中获取列

    我是一个 R 初学者 我被这个问题困扰了 我有一个数据框 并通过使用 split 函数创建了一个数据框列表 例如 dfList lt split mtcars mtcars cyl 现在我想检索特定数据帧的列 例如数据框 1 的第 2 列
  • Java 中的递归回溯解决填字游戏

    我需要在给定初始网格和单词的情况下解决填字游戏 单词可以多次使用或根本不使用 初始网格如下所示 这是一个单词列表示例 pain nice pal id 任务是填充占位符 水平或垂直长度 gt 1 像那样 p pain pal id i c