简单回溯暴力算法最坏情况下有效的数独谜题是什么?

2024-03-10

The "简单/幼稚的回溯暴力算法”、数独的“直接深度优先搜索”是众所周知并已实现的。

并且似乎不存在不同的实现。 (当我第一次写这个问题时..我想说我们可以完全标准化它,但措辞很糟糕..)

我认为这个人很好地描述了算法:https://stackoverflow.com/a/2075498/3547717 https://stackoverflow.com/a/2075498/3547717

编辑:所以让我用伪代码更详细地说明它......

var field[9][9]
set the givens in 'field'
if brute (first empty grid) = true then
    output solution
else
    output no solution
end if

function brute (cx, cy)
    for n = 1 to 9
        if (n doesn't present in row cy) and (n doesn't present in column cx) and (n doesn't present in block (cx div 3, cy div 3)) then
            let field[cx][cy] = n
            if (cx, cy) this is the last empty grid then
                return true
            elseif brute (next empty grid) = true then
                return true
            end if
            let field[cx][cy] = empty
        end if
    next n
end function

我想找到最需要时间的谜题。对于这种特定的“标准化”算法,我们可以称其为“最难”,但这并不像那些要求“最难的数独”的问题。

事实上,只要简单地旋转或翻转,这个定义下的“困难”谜题就可能变得超级简单。

根据“对于每个网格尝试数字1到9”的规则,它从1开始尝试,所以我们可以以某种方式让它通过使用适当的数字尝试更多,这样就不会出现排列问题。

数独谜题必须是valid,即它应该有 1 个解。Some guy http://norvig.com/sudoku.html有一个谜题需要 1439 秒,但由于没有答案而无效。

我定义所需的时间(或者说时间复杂度)相当于输入递归函数的次数。 (在我的实现中,它与上面的伪代码略有不同,因为最后一个入口,并确保唯一的解决方案等)

有没有什么好的方法来构造它,或者我们必须使用启发式算法等近似方法来找到不精确的解决方案?


我已经使用朴素策略(我在上面称为“简单”,它是唯一的)和 Peter Norvig 的“最少候选者优先”策略(我的实现是确定性的,但不是唯一的。正如 Peter 也提到的那样)实现了回溯。 python dict 的顺序会极大地改变结果,以防候选人数量平局)。

https://github.com/farteryhr/labs/blob/master/sudoku.c https://github.com/farteryhr/labs/blob/master/sudoku.c

无解方案一:

.....5.8....6.1.43.........1.5.........1.6...3.......553..... 61.........4.........

在我的笔记本电脑上花了 60 秒才得出无解结论,输入递归函数 2549798781 次(后面称为“循环”)。通过我的 LCF 实现,78308087 个循环在 30 秒内结束。这是因为寻找候选数最少的网格需要更多的操作,LCF策略的单个周期使用大约16倍的时间。

最难列表中最上面的一个:

4.....8.5.3......7......2......6.....8.4......1...... ...6.3.7.5..2.....1.4......

耗时3.0s,在第9727397个周期找到解,第142738236个周期确保解唯一。 (我的 LCF:0.004 秒内为 981/7216)

“困难”列表中的许多仍然很容易天真,尽管其中很大一部分需要 10^7 到 10^9 周期。

On 维基百科:数独求解算法 https://en.wikipedia.org/wiki/Sudoku_solving_algorithms#Backtracking (Original https://www.flickr.com/photos/npcomplete/2361922699)据说可以通过在开始时制作尽可能多的空网格和顶行 987654321 的排列来构造此类针对回溯算法的谜题。

好在测试..

......3.85..1.2......5.7.....4...1...9.......5.. ....73..2.1........4...9

需要1.4s,69175317个周期寻找解决方案,69207227个周期确保唯一解决方案。不如Peter提供的难点,但是还好,差不多找到解决方案后,搜索就结束了。这可能就是第一行按字典顺序排列的大小的工作原理。 (我的 LCF:0.023 秒内为 29206/46160)

是的,这些是显而易见的,我只是要求更好的方法......


还有其他方法 https://www.nature.com/articles/srep00725衡量数独难度的方法(通过求解)


数独分析师 http://www.stolaf.edu/people/hansonr/sudoku/analyst.htm会陷入Peter给出的多解谜题(天真的419195/419256,LCF 2529478/2529482,是的,有一些谜题让LCF做得更糟):

.....6..59.....82....8....45.........3.........6..3.54.. .325..6.................

这对于朴素回溯 (10008/76703) 和 LCF 回溯 (313/1144) 来说都很容易,但也会让 Sudoku Analyst 陷入困境。

..53.....8......2..7..1.5..4....53...1..7...6..32...8.. 6.5....9..4..3......97..


另一个更新:

最困难的数独谜题可通过简单的深度优先搜索算法快速解决 https://www.dcc.fc.up.pt/%7Eacm/sudoku.pdf

哈,终于有人也在找了,而且还给了一个超难的!以下有效谜题:

9..8......5......2..1...3.1.....6..4...... 7.7.86..3.1..4..2..

本文将该算法命名为SDFS,Straightforward Depth-First Search。作者所说的周期数是1553023932/1884424814,而我的实现是1305263522/1584688020。是的,在弹出计数器的确切位置上会有一些差异,但基本行为是一致的。在 repl.it 的服务器上,找到答案花了 97 秒,完成搜索花了 119 秒。


您可以通过记录所花费的时间/次数轻松生成最坏的情况。您的代码为解决困难的数独难题而执行的操作。您可以使用随机生成器来生成有效的数独谜题(或者)您可以从互联网上获取困难的数独谜题并对其运行代码以测量操作的时间/数量。一旦针对 10000 个此类情况运行代码,最慢的 5 个(以及未解决的情况)将是您的解决方案的最差情况。

在farter的评论后编辑

我意识到你想提高算法的效率。考虑到 CPU 能力相当高,一个 su-do-ku 谜题需要 97 秒!您可以减少时间

  1. 不要使用回溯,仅填写您知道解决方案的方格。编写一个贪心算法,为您永远不会改变的方块找到答案。
  2. 并行化您的搜索(同时查找多个方块的解决方案)
  3. 你的搜索应该涉及多种贪婪的方法......对于。例如。选择显示最多数字的线条/3x3 正方形/3x9/9x3 矩形,您更有可能显示该区域中的数字,这将减少整个拼图的运行时间。还可以找到特定区域中每个数字的频率,这将有助于快速查找数字。例如,如果在 3x9 正方形中显示出两个 3,则您更有可能显示第三个 3,因为该区域中的第三个 3 应该位于 3 个单元格之一中。
  4. 对于困难的谜题,添加记忆......例如。在某些情况下,您知道某一对号码适合一对单元格。但你不知道哪个细胞进入哪个细胞。在这种情况下,您可以确定其他 7 个数字不会出现在这些单元格中。记住这个否定标准并利用它来最大限度地减少搜索时间。

让我知道这是否有帮助。

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

简单回溯暴力算法最坏情况下有效的数独谜题是什么? 的相关文章

  • 分而治之算法找到两个有序元素之间的最大差异

    给定一个整数数组 arr 找出任意两个元素之间的差异 使得较大的元素出现在 arr 中较小的数字之后 Max Difference Max arr x arr y x gt y 例子 如果数组是 2 3 10 6 4 8 1 7 那么返回值
  • 在任意时间范围内找到最佳日/月/年间隔的算法?

    如果您有时间表 请说 March 19 2009 July 15 2011 是否有一种算法可以将该时间范围分解为 March 19 2009 March 31 2009 complete days April 1 2009 December
  • 是否有一种算法可以在线性时间内计算数组反转?

    我知道有多少倒转 en wikipedia org wiki Inversion 28discrete mathematics 29 in an n 元素数组可以在 O n log n 操作使用增强型归并排序 http www geeksf
  • Haskell 排列库函数 - 请澄清一下?

    这是代码permutationsHaskell 中的函数Data List module permutations a gt a permutations xs0 xs0 perms xs0 where perms perms t ts i
  • 如何在 C# 中以编程方式创建柔和的颜色?

    根据所需的颜色数量均匀分布地生成它们 如果指定的计数为 8 则看起来像这样 List
  • 如何在C中实现带连分数的自然对数?

    这里我有一个小问题 根据这个公式创建一些东西 这就是我所拥有的 但它不起作用 弗兰基 我真的不明白它应该如何工作 我尝试用一 些错误的指令对其进行编码 N 是迭代次数和分数部分 我认为它会以某种方式导致递归 但不知道如何 谢谢你的帮助 do
  • 为什么这个算法的Big-O复杂度是O(n^2)?

    我知道这个算法的大O复杂度是O n 2 但我不明白为什么 int sum 0 int i 1 j n n while i lt j sum 即使我们设定了j n n一开始 我们在每次迭代期间递增 i 并递减 j 因此最终的迭代次数不应该比n
  • 总和不小于 key 的数组的最小子集

    给定一个数组 假设为非负整数 我们需要找到最小长度子集 使得元素之和不小于 K K 是作为输入提供的另一个整数 是否有可能找到时间复杂度为 O n n 的大 oh 的解决方案 我目前的想法是这样的 我们可以在 O n log n 中对数组进
  • JavaScript 中的埃拉托斯特尼筛法对大量数据无限运行

    我一直在尝试写埃拉托斯特尼筛法 http en wikipedia org wiki Sieve of EratosthenesJavaScript 中的算法 基本上我只是按照以下步骤操作 创建从 2 到 n 1 的连续整数列表 令第一个素
  • 删除近排序数组中未排序/离群元素

    给定一个像这样的数组 15 14 12 3 10 4 2 1 我如何确定哪些元素乱序并删除它们 在本例中为数字 3 我不想对列表进行排序 而是检测异常值并将其删除 另一个例子 13 12 4 9 8 6 7 3 2 我希望能够删除 4 和
  • 连接红黑树

    OCaml 标准库有一个很棒的Set使用非常有效的分而治之算法来计算的实现union两套 我相信它会从一组中获取整个子树 而不仅仅是单个元素 并将它们插入到另一组中 并在必要时重新平衡 我想知道这是否需要 OCaml 使用的 AVL 树中保
  • 颜色变换器功能上的堆栈溢出错误

    我有两种颜色 红色 和 鲑鱼色 我需要动态创建面板以及面板背景颜色 这些颜色必须介于两种颜色之间 红色 public Color x y protected void Page Load object sender EventArgs e
  • 查找嵌套列表中元素的索引?

    我有一个类似的列表 mylist lt list a 1 b list A 1 B 2 c list C 1 D 3 是否有一种 无循环 方法来识别元素的位置 例如如果我想用 5 替换 C 的值 并且在哪里找到元素 C 并不重要 我可以这样
  • 我如何开始玩五子棋?

    我读到Gomoku http en wikipedia org wiki Gomoku它可以使用 Minimax 和 Alpha Beta 剪枝算法来实现 所以 我阅读了这些算法 现在了解了游戏将如何解决 但是当我坐下来编写代码时 我面临着
  • Java 中查看 ArrayList 是否包含对象的最有效方法

    我有一个 Java 对象的 ArrayList 这些对象有四个字段 我用其中两个字段来将对象视为与另一个对象相等 我正在寻找最有效的方法 给定这两个字段 以查看数组是否包含该对象 问题在于这些类是基于 XSD 对象生成的 因此我无法修改类本
  • 添加边后更新最大流量

    考虑我们有一个网络流量 并使用 Edmond Karp 算法 我们已经拥有网络上的最大流量 现在 如果我们向网络添加任意边 具有一定容量 更新最大流量的最佳方法是什么 我正在考虑更新关于新边缘的残差网络 并再次寻找增强路径 直到找到新的最大
  • 寻找公共子集的算法

    I have N number of sets Si of Numbers each of a different size Let m1 m2 mn be the sizes of respective sets mi Si and M
  • while循环的时间复杂度是多少?

    我正在尝试找出 while 循环的时间复杂度 但我不知道从哪里开始 我了解如何找到 for 循环的复杂性类别 但是当涉及到 while 循环时 我完全迷失了 关于从哪里开始有什么建议 提示吗 这是一个问题的示例 x 0 A n some a
  • 使用递归返回嵌套列表中第二小的数字

    我必须归还第二小的使用递归的 python 列表中的数字 以及no loops 我所做的是创建一个辅助函数 它返回列表中 最小 第二小的 值的元组 然后我只取tuple 1 in my second smallest func def s
  • 从列表中选择项目以求和

    我有一个包含数值的项目列表 我需要使用这些项目求和 我需要你的帮助来构建这样的算法 下面是一个用 C 编写的示例 描述了我的问题 int sum 21 List

随机推荐