【问题标题】:The Dancing Links Algorithm - An explanation that is less explanatory but more on implementation?The Dancing Links Algorithm - 解释性较少但更多关于实施的解释?
【发布时间】:2009-10-05 05:03:55
【问题描述】:

我一直在研究数独求解器,我当前的求解器使用回溯算法,但仍然需要很长时间。

我希望在大多数情况下将其缩短到不到一秒。因此,我决定用跳舞链接算法重写它,因为它是更好的蛮力方法之一,尤其适用于数独难题等约束问题。

我尝试阅读 Wiki 和上面的 Knuth's paper,但是它们都有点难以理解并且非常冗长。

我也读过Supedia的版本,似乎一旦到了数独的实现,它就变得太抽象了。

有人可以尝试解释 Dancing Links 算法,而不是从它的推导而是它的实现? (以数独为例就好了)

谢谢!

【问题讨论】:

  • 此链接的完整源代码不再可用。并且其中的代码 sn-ps 有一些错误。特别是 unlock(ColumnNode c) 方法。在那篇文章中,该代码是覆盖方法的副本,其中 for 循环中的某些内容已更改。内层循环的迭代器需要向左走而不是向右走,并且需要将链接恢复到原来的样子,不要重复覆盖操作。示例:leftNode.getUp().setDown(leftNode);而不是 leftNode.getUp().setDown(leftNode.getDown());
  • 我创建了这个 Sudoku Solver Visualizer,它实现了 Dancing Links 和其他几种算法,包括贪婪最佳优先搜索和回溯。也许你会发现它很有帮助。代码可以在here 找到,虽然它很混乱。我建议只检查可视化工具。
  • 我还使用 Dancing Links 为 Sudoku 1 编写了 2 种方法,另一种使用 Hidden Singles。 github.com/Elementrix08/Sudoku

标签: algorithm sudoku


【解决方案1】:

您可能对my implementation in javascript 感兴趣。


首先您必须了解 Exact Cover。一个精确的覆盖问题是一个问题,你有一堆选择,一组约束,你的挑战是选择一堆选项,这些选项将恰好满足每个约束一次。

例如,考虑某人创建他们的冰舞套路的情况。他们有许多技巧需要向评委展示,并且不想多次表演任何技巧。他们有许多序列,这些序列是可以组合在一起的技巧组,他们希望选择理想的序列选择来一次性涵盖所有技巧。在这个例子中,约束是他们必须执行每一个技巧。选择是他们可以纳入日常活动的可能顺序。

表示此类问题的一个好方法是绘制一个表格,其中约束是列,选择是行,并且在单元格中有一个大 X,其中特定选择满足该约束。

事实证明,给定正确的约束和选择,数独可以描述为精确覆盖问题。


好吧,假设你已经明白了,现在你需要了解算法 X。Knuth 说:“算法 X 只是对明显的试错方法的陈述。(事实上,我想不出一般而言,任何其他合理的方式来完成这项工作。)”。所以这是我对算法 X 的描述:

  1. 如果您的表格没有列,请停止 - 您已经解决了。如果您存储了部分解决方案,那么它实际上是一个真正的解决方案,请将其退回。
  2. 选择一列(代表一个约束)。
  3. 在该列中查找带有叉号的行(表示满足该约束的选择)。将其添加到存储潜在解决方案的某种结构中。如果找不到行,请放弃 - 没有解决方案。
  4. 假设您在 3 中找到的行在解决方案中,因此删除该行中包含 X 的所有列。在删除所有这些列的同时,还要删除在要删除的列中包含 X 的所有行(因为您已经满足了约束,因此您无法选择再次满足它的内容)。
  5. 现在递归地尝试求解简化表。如果不能,请从潜在解决方案结构中删除您尝试过的行,恢复您在第 3 步和第 4 步中删除的所有行和列,然后尝试不同的行。如果行数用完了,那就放弃吧 - 没有解决办法。

既然你明白了,你就可以理解跳舞的链接了。 Dancing Links 是一种有效实现该算法的方法。跳舞链接的关键在于,在链表中,当您删除一个节点时(可以通过修改其邻居的指针来有效地完成),您删除的节点具有您需要将其添加回来的所有信息到链表(如果你猜到它是解决方案的一部分时你错了)。再加上如果你把所有的链表都变成循环的,那么你会突然失去很多特殊情况,这几乎就是所有的跳舞链接。

【讨论】:

  • 我想知道您是否可以看一下我正在尝试解决的puzzle,并告诉我是否可以通过跳舞链接解决它。乍一看类似于 Polyonimos 拼图,但你可以有重叠。那么这个谜题是否也可以被认为是完全覆盖并通过跳舞链接来解决?
【解决方案2】:

虽然这个问题很老了,但我想我会补充一下:

这个页面让算法很容易理解:Zendoku writeup。在我在那个链接上读到它之前,我一直认为这一定是一个超级高级的算法,但实际上一旦你可以将它可视化,它就是一个非常巧妙但简单的解决方案。

另外,C# 中的my implementation 应该相当容易阅读......我敢肯定,将各种类拆分为不同的文件会很有帮助。
它主要是来自 Knuth 的 pdf 的直接实现,但有一些面向对象的优化(实际上自从几个月前我这样做以来,我不太记得我偏离了 pdf 多少)

【讨论】:

  • 指向您的 c# 实现的链接已失效。你有机会分享吗?我试图弄清楚如何在内存中可视化列表。
  • 可能晚了,但它是环形结构中的双链表:从任何单元格你可以上下左右移动,当你到达边缘时,你会跳到另一边
  • 只是为了更新,两个链接对我来说都很好,我很确定我验证了它们在第一次发表评论时仍然有效(我的实现是一个公共 github 要点,所以应该一样稳定就像现在的任何开源项目一样)
  • 我想知道您是否可以看一下我正在尝试解决的puzzle,并告诉我是否可以通过跳舞链接解决它。乍一看类似于 Polyonimos 拼图,但你可以有重叠。那么这个谜题也可以被认为是精确的掩护并通过跳舞链接来解决吗? – 胡安·卡洛斯·奥罗佩萨 9 分钟前
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-20
  • 1970-01-01
  • 2013-04-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多