Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 解决填字游戏_Java_Algorithm_Backtracking_Brute Force - Fatal编程技术网

Java 解决填字游戏

Java 解决填字游戏,java,algorithm,backtracking,brute-force,Java,Algorithm,Backtracking,Brute Force,我有一个纵横字谜和一个可以用来解决它的单词列表(单词可以放置多次,甚至一次也不能放置)。对于给定的纵横字谜和单词列表,总是有一个解决方案 我寻找了解决这个问题的线索,发现它是NP完全的。我的最大纵横字谜大小是250乘250,列表的最大长度(可以用来解决它的字数)是200。我的目标是通过暴力/回溯来解决这种大小的纵横字谜,这应该可以在几秒钟内完成(这是我的粗略估计,如果我错了请纠正我) 例如: 可用于解决纵横字谜的给定单词列表: 能 音乐 金枪鱼 嗨 给定的空纵横字谜(X是无法填写的字段,需要

我有一个纵横字谜和一个可以用来解决它的单词列表(单词可以放置多次,甚至一次也不能放置)。对于给定的纵横字谜和单词列表,总是有一个解决方案

我寻找了解决这个问题的线索,发现它是NP完全的。我的最大纵横字谜大小是250乘250,列表的最大长度(可以用来解决它的字数)是200。我的目标是通过暴力/回溯来解决这种大小的纵横字谜,这应该可以在几秒钟内完成(这是我的粗略估计,如果我错了请纠正我)

例如:

可用于解决纵横字谜的给定单词列表:

  • 音乐
  • 金枪鱼
给定的空纵横字谜(X是无法填写的字段,需要填写空字段):

解决方案:


现在,我当前的方法是将纵横字谜表示为二维数组,并搜索空白(在纵横字谜上进行两次迭代)。然后我根据单词的长度将单词与空格进行匹配,然后我尝试将所有单词组合与长度相同的空格进行匹配。这种方法变得非常混乱非常快,我在尝试实现它时迷失了方向,有更优雅的解决方案吗?

你是对的问题是
NP
-完整的。所以你最好的办法就是用蛮力来解决它(如果你找到一个多项式算法,请告诉我,我们都可以变得富有=)

我建议你看看。它将允许您为纵横字谜问题编写一个优雅(但考虑到您的输入大小,速度较慢)的解决方案

如果您需要更多鼓舞人心的材料,请查看使用回溯作为导航解决方案树的方法

请注意,有些算法在实践中可能比纯蛮力(尽管仍然具有指数复杂性)表现得更好。 此外,快速搜索“学者”会发现大量关于该主题的论文,您可能想看看,例如:


填字游戏是一个约束满足问题,通常是NP完全问题,但有许多解决方案可以将最有效的算法应用于您指定的约束问题。Z3 SMT求解器可以非常轻松地大规模解决这些问题。您所要做的就是编写一个Java程序,将纵横字谜转换为SMT问题,解算器可以理解,然后将其交给解算器解算。Z3有Java绑定,所以它应该非常简单。我已经为解决下面的第一个示例编写了Z3代码。按照Java程序中的模式来指定任意大的十字路口难题对您来说应该不难

; Declare each possible word as string literals
(define-const str1 String "tuna")
(define-const str2 String "music")
(define-const str3 String "can")
(define-const str4 String "hi")

; Define a function that returns true if the given String is equal to one of the possible words defined above.
(define-fun validString ((s String)) Bool 
    (or (= s str1) (or (= s str2) (or (= s str3) (= s str4)))))

; Declare the strings that need to be solved
(declare-const unknownStr1 String)
(declare-const unknownStr2 String)
(declare-const unknownStr3 String)
(declare-const unknownStr4 String)

; Assert the correct lengths for each of the unknown strings.
(assert (= (str.len unknownStr1) 4))
(assert (= (str.len unknownStr2) 5))
(assert (= (str.len unknownStr3) 3))
(assert (= (str.len unknownStr4) 2))

; Assert each of the unknown strings is one of the possible words.
(assert (validString unknownStr1))
(assert (validString unknownStr2))
(assert (validString unknownStr3))
(assert (validString unknownStr4))

; Where one word in the crossword puzzle intersects another assert that the characters at the intersection point are equal.
(assert (= (str.at unknownStr1 1) (str.at unknownStr2 1)))
(assert (= (str.at unknownStr2 3) (str.at unknownStr4 1)))
(assert (= (str.at unknownStr2 4) (str.at unknownStr3 0)))

; Solve the model
(check-sat)
(get-model)

我推荐Z3 SMT解算器,但还有很多其他约束解算器。您不需要实现自己的约束求解算法,正如您不需要实现自己的排序算法一样

为了使这个问题更容易解决,我将把它分解成更小更容易的问题。请注意,我没有包括代码/算法,因为我相信这在这里不会有帮助(如果我们想要最好的代码,那么会有索引、数据库和黑魔法,只要看到它,你的头就会爆炸)。相反,这个答案试图通过谈论思想方法来回答这个问题,这将有助于OP使用最适合读者的方法解决这个问题(以及未来的问题)

你需要知道什么 此答案假设您知道如何执行以下操作

  • 创建和使用具有属性和函数的对象
  • 选择一个数据结构,该结构对于您希望对其内容执行的操作有效(不一定好)
为您的空间建模 因此,将填字游戏加载到一个n×m矩阵(2D数组,这里称为“网格”)中非常容易,但从实用角度来看,这是很容易听到的。因此,让我们从将纵横字谜从网格解析为合法对象开始

就您的程序需要知道的而言,填字游戏中的每个条目都有4个属性

  • 网格中第一个字母的X-Y坐标
  • 方向(向下或穿过)
  • 字长
  • 字数
  • 绑定索引映射
    • 关键字:与其他条目共享的单词索引
    • 值:与之共享索引的项
    • (您可以将其设置为元组,并包含来自其他条目的共享索引,以便于参考)
  • 您可以在扫描时根据这些规则在网格中找到这些

  • 如果第1行向上关闭,第1行向下打开,则这是向下单词的开始索引。(向下扫描长度。对于绑定索引,将打开左侧或右侧空间。向左扫描以获取链接的条目坐标id)
  • 与1相同,但在单词之间旋转(您可以在扫描1的同时执行此操作)
  • 在纵横字谜对象中,可以使用坐标+方向作为键来存储条目,以便于参考和与文本网格表单的转换

    使用您的模型 现在应该有一个包含纵横字谜条目集合的对象,这些条目包含它们的相关索引绑定。现在需要找到一组满足所有条目的值

    你的输入对象应该有像
    isValidEntry(str)
    这样的助手方法来检查给定的值和纵横字谜的当前状态,我可以把这个词放在这里吗?通过使模型中的每个对象负责其自己的逻辑级别,一个思想层上的问题代码可以调用逻辑,而不必担心它的实现(在本例中,您的解算器不必担心逻辑的值是否有效,它只需询问
    isValidEntry

    如果您已经正确地完成了上述操作,那么解决问题就只需迭代所有wo