Java 解决填字游戏
我有一个纵横字谜和一个可以用来解决它的单词列表(单词可以放置多次,甚至一次也不能放置)。对于给定的纵横字谜和单词列表,总是有一个解决方案 我寻找了解决这个问题的线索,发现它是NP完全的。我的最大纵横字谜大小是250乘250,列表的最大长度(可以用来解决它的字数)是200。我的目标是通过暴力/回溯来解决这种大小的纵横字谜,这应该可以在几秒钟内完成(这是我的粗略估计,如果我错了请纠正我) 例如: 可用于解决纵横字谜的给定单词列表:Java 解决填字游戏,java,algorithm,backtracking,brute-force,Java,Algorithm,Backtracking,Brute Force,我有一个纵横字谜和一个可以用来解决它的单词列表(单词可以放置多次,甚至一次也不能放置)。对于给定的纵横字谜和单词列表,总是有一个解决方案 我寻找了解决这个问题的线索,发现它是NP完全的。我的最大纵横字谜大小是250乘250,列表的最大长度(可以用来解决它的字数)是200。我的目标是通过暴力/回溯来解决这种大小的纵横字谜,这应该可以在几秒钟内完成(这是我的粗略估计,如果我错了请纠正我) 例如: 可用于解决纵横字谜的给定单词列表: 能 音乐 金枪鱼 嗨 给定的空纵横字谜(X是无法填写的字段,需要
- 能
- 音乐
- 金枪鱼
- 嗨
现在,我当前的方法是将纵横字谜表示为二维数组,并搜索空白(在纵横字谜上进行两次迭代)。然后我根据单词的长度将单词与空格进行匹配,然后我尝试将所有单词组合与长度相同的空格进行匹配。这种方法变得非常混乱非常快,我在尝试实现它时迷失了方向,有更优雅的解决方案吗?你是对的问题是
NP
-完整的。所以你最好的办法就是用蛮力来解决它(如果你找到一个多项式算法,请告诉我,我们都可以变得富有=)
我建议你看看。它将允许您为纵横字谜问题编写一个优雅(但考虑到您的输入大小,速度较慢)的解决方案
如果您需要更多鼓舞人心的材料,请查看使用回溯作为导航解决方案树的方法
请注意,有些算法在实践中可能比纯蛮力(尽管仍然具有指数复杂性)表现得更好。
此外,快速搜索“学者”会发现大量关于该主题的论文,您可能想看看,例如:
; 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使用最适合读者的方法解决这个问题(以及未来的问题) 你需要知道什么 此答案假设您知道如何执行以下操作
- 创建和使用具有属性和函数的对象
- 选择一个数据结构,该结构对于您希望对其内容执行的操作有效(不一定好)
- 关键字:与其他条目共享的单词索引
- 值:与之共享索引的项
- (您可以将其设置为元组,并包含来自其他条目的共享索引,以便于参考)
isValidEntry(str)
这样的助手方法来检查给定的值和纵横字谜的当前状态,我可以把这个词放在这里吗?通过使模型中的每个对象负责其自己的逻辑级别,一个思想层上的问题代码可以调用逻辑,而不必担心它的实现(在本例中,您的解算器不必担心逻辑的值是否有效,它只需询问isValidEntry
)
如果您已经正确地完成了上述操作,那么解决问题就只需迭代所有wo