【问题标题】:Sudoku solver, special case solving数独求解器,特殊情况求解
【发布时间】:2013-03-08 08:31:43
【问题描述】:

我正在开发一个带有递归回溯的数独求解器,除了一件事之外,它几乎完成了。如果我将重复项放在谜题中的某个位置(例如顶角的 1,1),即使它不是一个可解的谜题,它也可以一直尝试找到解决方案。

非常感谢任何帮助!

罗伯

【问题讨论】:

  • 我建议您使用 debugger(或 here,如果您使用 IntelliJ)逐行浏览您的程序。
  • 我认为应该在solve方法中,虽然不完全确定如何写。也许另一种方法呢?抱歉,我对 Java 很陌生。也许有人可以给你一个代码的sn-p。但是,是的,我的猜测可能是在求解方法中,或者为 checkRow 和 checkColumn 编写一个新方法。
  • 我不明白你的意思。数独谜题的每个插槽都有一个数字,那么重复的是什么?您是在谈论解决方案还是用户在尝试解决方案时输入了什么?请记住,除了我们(可能)了解的数独之外,您的读者在这里没有任何背景。
  • @rcook 对不起,会尽量澄清解释,检查编辑
  • ...我有点担心你会一概而论ArrayIndexOutOfBoundsException - 这种类型的错误通常表示某种编程错误(通常是一个错误)。特别是因为您随后返回“已解决”!找出导致错误的原因,然后消除它。

标签: java recursion sudoku backtracking


【解决方案1】:

要实现 Validate 类,你不能在你的 solve 方法中写 Validate.validate(); 吗?希望对您有所帮助。

【讨论】:

  • 嗯,我认为结构是正确的,但不确定你应该在 parenteses 中包含什么。也许有人可以尝试一下,因为我认为它部分正确。
【解决方案2】:

这不一定是答案,但它应该对您有所帮助。我以前为宏程序做过这种事情,它是可用的最高评价的。

数独求解器可能是一个相当大的挑战。判断一个动作是否正确的唯一方法是它是绝对的还是后来被证明的。这可能会导致相当大的挑战,因为结局是基于当前的情况和动作。这意味着您可以将其作为排列处理。你可以遍历每个方块并找出它有哪些可能的数字。从那里,您可以获得一两个已定义的正方形。基于此,有许多可能的方法可以到达终点。

当谜题被解决(没有错误 - 每个方块都填满)或出现错误时,将定义一个“终点”。

基于此,您可以将每个动作视为一个节点,然后围绕可能的动作构建一个树系统。

例如:

8 7 1   2 _ _   6 9 3
2 9 6   3 8 7   1 _ _

这只是一个小例子,但基于它,分别扫过每一行,然后每一列我们可以生成可能的数字:

(5, 1) -> [4, 5]
(6, 1) -> [4, 5]
(8, 2) -> [4, 5]
(9, 2) -> [4, 5]

基于此,以及提供给我们的解决方案,我们可以看到正好有 4 种可能的解决方案:

8 7 1   2 4 5   6 9 3
2 9 6   3 8 7   1 4 5

-或-

8 7 1   2 5 4   6 9 3
2 9 6   3 8 7   1 4 5

-或-

8 7 1   2 4 5   6 9 3
2 9 6   3 8 7   1 5 4

-或-

8 7 1   2 5 4   6 9 3
2 9 6   3 8 7   1 5 4

虽然这些信息不足以解决整个难题并找出哪个“正确”,但可以将其标准化并用于创建类似的系统并很快找到解决方案。

因此,您可以将所有这 4 种可能性添加到一棵树中,每个都从原始分支:

8 7 1   2 _ _   6 9 3
2 9 6   3 8 7   1 _ _

然后递归处理它们。

希望这会有所帮助!

【讨论】:

    【解决方案3】:

    关于重复项,我建议为每个单元格保留一个可能的数字列表,当您尝试解决单元格时,您可以将此列表与匹配的行、列和框进行比较,这样可以防止创建重复项.有了这个,您可以解决更简单的难题而无需回溯。如果你卡住了,那么使用回溯继续......

    【讨论】:

    • 存储“可能”值列表的问题是什么时候更新该列表?也就是说,当您放置数字时,您永远不会知道该数字是否属于那里(除非它是唯一可能的值)
    • @Cruncher 我不知道他是从空白拼图开始的。我假设有一个给定的难题要解决。我提到了更简单的那些,它们的单元格只有 1 个可能的值。首先,您将初始化列表,并且在求解过程中,每当您输入一个数字时,您都会更新相应行、列和框中的所有单元格。我实现了这个并且它有效,但它只是我的数独求解器的第一部分,因为它只能完全解决更简单的难题。
    • @Basic 这基本上只是为了教育目的,我希望最终用户编写他/她自己的谜题,偶尔可能会出现两个数字重复的人为错误,这就是我想要防止的。
    • @Rob 我是“为了好玩”而写我的,因为当我自己无法解决这个难题时,我感到很沮丧... :) 我的回答适用于您的情况:当用户输入number 你应该检查相应的行、列和框,看它是否重复。如果是,您可以清除该单元格并通知用户。您可以按照我的建议保留列表,或者您可以使用单元格坐标来获取需要检查的行、列和框。我更喜欢列表,因为代码会更简单。你会有 List.
    【解决方案4】:

    您想检测无效的情况,因此您应该在调用求解器之前检查它。您的求解器本身不会创建无效的解决方案...

    【讨论】:

      【解决方案5】:

      你知道回溯的方式是当你的谜题遇到矛盾时,所以在每一步你都应该运行一个“验证”方法,如果谜题是非法的,那么你所做的最后一步就是非法的。

      当你发现你的举动是非法的,你可以递归地回溯并继续前进。

      另外,请注意,这是一种相当幼稚的方法,也许一些数独专家有更好的算法,但这种蛮力应该可以解决问题。

      【讨论】:

      • 如果 square (1, 1) 被分配了错误的值怎么办,但它当时有效。谜题的其余部分将尝试从那时起解决。它很快就会出现一个不对应的错误,即使它试图做出的动作是正确的,也会失败。
      • 虽然我不太确定如何实现这样的方法。
      • 当时不是问题,但它会导致正确的问题。但是当它在路上遇到问题时,它会退回一步,并尝试新的价值观。在尝试所有值并发现它们都矛盾后,它会回溯一个级别,最终会回来并修复最初导致矛盾的原因。
      • @Rob,方法比较简单。您遍历所有行、列和框,如果任何集合有双精度,则返回 false
      • 这与您实际拥有的支票相似。我的建议是天真地放置数字,然后检查是否有问题。另外,这让我很好奇,如果您一开始就不允许重复,您是如何遇到这些问题的?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 2014-06-06
      • 1970-01-01
      相关资源
      最近更新 更多