我的启发式算法是否正确? (数独求解器)

时间:2012-04-12 23:51:58

标签: algorithm prolog heuristics sudoku

首先 - 这是一个作业 - 但它主要是一个理论问题,而不是一个实际问题,我只是要求确认我是否正确思考或任何提示,如果我不是。

我被要求编译一个简单的数独求解器(在 Prolog 上,但现在不是那么重要),唯一的限制是它必须使用Best-First Algorithm的启发式函数。我能够提出的唯一启发函数解释如下:

1. Select an empty cell. 
  1a. If there are no empty cells and there is a solution return solution.
      Else return No.
2. Find all possible values it can hold. %% It can't take values currently assigned to cells on the same line/column/box.
3. Set to all those values a heuristic number starting from 1.
4. Pick the value whose heuristic number is the lowest && you haven't checked yet.
   4a. If there are no more values return no.
5. If a solution is not found: GoTo 1.
   Else Return Solution.

// I am sorry for errors in this "pseudo code." If you want any clarification let me know.

我这样做是对的,还是有其他方法,我的是假的? 提前谢谢。

3 个答案:

答案 0 :(得分:1)

我将使用的启发式是:

  1. 反复找到任何只能插入一个可能数字的空格。用适合的1-9填充它们。
  2. 如果每个空白区域都有两种或更多种可能性,请将游戏状态推入堆叠,然后选择一个随机方块以填充随机值。
  3. 转到第1步。
  4. 如果你设法填补每个方格,你就找到了一个有效的解决方案。

    如果你达到没有有效选项的点,将最后一个游戏状态弹出堆栈(即回溯到你最后一次随机选择。)做出不同的选择,再试一次。


    作为一个有趣的旁注,你被告知使用贪婪的启发式方法来做到这一点,但是数独实际上可以简化为布尔可满足性问题(SAT问题)和solved using a general-purpose SAT solver。这非常优雅,实际上可以更快而不是启发式方法。

答案 1 :(得分:1)

当我在Prolog中自己编写一个数独求解器时,我使用的算法如下:

  1. 过滤掉已经解决的单元格(即开始时的给定值)
  2. 对于每个单元格,构建一个包含其所有邻居(即20个单元格)的列表。
  3. 对于每个单元格,构建一个包含所有可能值的列表(完成上述操作后很容易)
  4. 在包含要解决的所有单元格的列表中,在顶部
  5. 上放置一个值最小值的单元格
  6. 如果顶部单元格剩余0,则转到7,否则转到6,如果列表为空,则表示您有解决方案。
  7. 对于列表顶部的单元格:在单元格的可能值中选择一个随机数。在其邻居的所有可能值中删除此值。转到5。
  8. 回溯(即在Prolog中失败)
  9. 此算法始终首先对“解决最多”的单元格进行排序,并尽早检测到故障。与解决随机单元格的算法相比,它减少了很多求解时间。

答案 2 :(得分:0)

您所描述的是最受约束的变量启发式算法。它拾取具有最少可能性的单元格,然后从该单元格开始递归地递归分支。这种启发式算法在深度优先搜索算法中速度极快,因为它可以在根部附近检测到碰撞,而搜索树仍然很小。

以下是C#中最受约束的变量启发式的实现:Exercise #2: Sudoku Solver

本文还包含了通过此算法对Sudoku单元的总访问次数的分析 - 它非常小。它几乎看起来像启发式在第一次尝试中解决了数独。