7

如果数独谜题具有唯一解,则它是最小的(也称为不可约解),但删除任何数字都会产生具有多个解的谜题。换句话说,每个数字都是确定解决方案所必需的。

我有一个生成最小数独的基本算法:

  • 生成一个完整的谜题。
  • 以随机顺序访问每个单元格。对于每个访问的单元格:
    • 暂时去掉它的数字
    • 使用递归回溯算法两次解决难题。一个求解器以正序尝试数字 1-9,另一个以相反的顺序尝试。从某种意义上说,求解器正在遍历包含所有可能配置的搜索树,但来自相反的两端。这意味着如果拼图有唯一解,则这两个解将匹配
    • 如果谜题有唯一解,则永久删除该数字;否则,将其放回原处。

这种方法可以保证产生一个最小的谜题,但它很慢(我的电脑上 100 毫秒,智能手机上几秒钟)。我想减少解决的次数,但我能想到的所有明显方法都是不正确的。例如:

  • 添加数字而不是删除它们。 这样做的好处是,由于最小的谜题至少需要 17 个填充数字,所以前 17 个数字保证没有唯一的解决方案,减少了解决的数量。不幸的是,由于单元格是按随机顺序访问的,因此会在“锁定”唯一解决方案的一个重要数字之前添加许多不必要的数字。例如,如果添加的前 9 个单元格都在同一列中,则那里有大量冗余信息。
  • 如果没有其他数字可以替代当前的数字,请将其保留,不要解决难题。因为检查一个展示位置是否合法比解决两次难题要快数千倍,这可以节省大量时间。但是,仅仅因为现在没有其他合法数字并不意味着一旦我们删除其他数字就不会再有。
  • 由于我们生成了原始解决方案,因此每个单元格只解决一次,看看它是否与原始解决方案匹配。这不起作用,因为原始解决方案可能位于可能解决方案的搜索树中的任何位置。例如,如果原始解决方案靠近树的“左侧”,并且我们从左侧开始搜索,我们将错过树右侧的解决方案。

我还想优化求解算法本身。困难的部分是确定解决方案是否是唯一的。我可以进行微优化,例如为每个单元格创建合法位置的位掩码,如这篇精彩的帖子中所述。然而,更高级的算法,如 Dancing Links 或模拟退火,并非旨在确定唯一性,而只是为了找到任何解决方案。

如何优化我的最小数独生成器?

4

2 回答 2

0

我有一个想法on the 2nd option,如果您为第一个 17 号码添加 3 次额外检查,您的建议会更好

  • 查找 1-9 之间的 17 个随机数的列表
  • 在提供的随机位置添加每个项目

    1. 这些新添加的数字不符合数独的 3 个基本标准

      • 同一行没有相同的数字
      • 同一列中没有相同的数字
      • 相同的 3x3 矩阵中没有相同的数字
    2. 如果条件 1 失败,则移至下一列或下一行并再次检查 3 个基本条件。

    3. 如果没有下一行(即在第 9 列或第 9 行),则在填充 17 个字符后添加到第 1 列,在此运行您的求解器逻辑并寻找您的唯一解决方案。
于 2013-01-04T05:52:48.757 回答
0

以下是我通过(高度近似的)速度提高百分比实现的主要优化:

  • 使用位掩码来跟踪每个单元格中满足哪些约束(行、列、框)。这使得查找展示位置是否合法的速度更快,但制作展示位置的速度更慢。使用位掩码生成谜题而不只是解决它们的一个复杂因素是可能必须删除数字,这意味着您需要将三种类型的约束作为不同的位来跟踪。一个小的进一步优化是将每个数字和每个约束的掩码保存在数组中。 40%
  • 如果需要太长时间,则将生成超时并重新启动。见这里。最佳策略是在每次失败生成后增加超时时间,以减少无限期继续的机会。 30%,主要来自减少最坏情况的运行时间。
  • mbeckish 和 user295691 的建议(请参阅原始帖子的评论)。 25%
于 2013-01-12T17:23:01.637 回答