算法——舞蹈链算法

一,基本概念

算法简介 

        舞蹈链算法(Dancing Links,简称 DLX)是一种高效解决精确覆盖问题的算法,实际上是一种数据结构,可以用来实现 X算法,以解决精确覆盖问题。由高德纳(Donald E. Knuth)提出 。

精准覆盖 

        什么是精确覆盖(Exact Cover)问题呢?就是在一个全集X中若干子集的集合为S。S* 是 S的一个子集,当且仅当X中的每一个元素在S*中恰好出现一次时,S*称之为一个精确覆盖。在计算机科学中,精确覆盖问题指找出这样的一种覆盖,或证明其不存在。这是一个NP-完全问题。

舞蹈链

        其实是一种特殊的数据结构,用于高效地实现对精确覆盖问题的求解。它基于双向循环链表,每个节点除了包含指向左右节点的指针外,还包含指向上方和下方节点的指针,这种结构使得在搜索过程中能够快速地对链表进行插入、删除和恢复操作。

数据结构设计

每个1的节点包含四个指针:leftrightupdown,形成双向十字链表。

每列有一个列头节点,记录该列中1的数量(用于优化搜索顺序)。

算法流程

  1. 选择列:优先选择当前剩余1最少的列(减少搜索分支)。

  2. 覆盖列:删除该列及其关联的所有行(避免后续搜索冲突)。

  3. 递归搜索:对剩余矩阵重复上述步骤。

  4. 回溯恢复:若当前路径无解,恢复被删除的列和行,尝试其他分支。

  5. 结束条件:当舞蹈链中的所有列都被覆盖(即矩阵中所有列都被删除)时,找到了一个精确覆盖解;如果遍历完所有可能的分支都没有找到解,则说明该问题无解。

 二,示例

例如,S = {A,B,C,D,E,F} 是全集 X = {1,2,3,4,5,6,7} 的一个子集的集合,其中:

A = {1, 4, 7}

B = {1, 4}

C = {4, 5, 7}

D = {3, 5, 6}

E = {2, 3, 6, 7}

F = {2, 7}

那么,S的一个子集 S* = {B, D, F} 是X的一个精确覆盖,因为 X 中的每个元素恰好在S*中出现了一次。

可以用0-1矩阵来表示精确覆盖问题。我们用矩阵的每行表示S的一个元素,也就是X的一个子集;用矩阵的每列表示X的一个元素。矩阵中的1代表这一列的元素存在于这一行对应的子集中,0代表不存在。那么精确覆盖问题可以转化成求出矩阵若干行的集合,使得集合中的每一列恰好都有一个1。

比如前面的问题可以用矩阵的形式表示成

步骤1

那么选择红色的B,D,F能满足每列都恰好包含一个1。

可以用 Knuth 提出的X算法来解决精确覆盖问题。X算法是一个非确定性的深度优先回溯算法。它的具体步骤如下:

1. 如果矩阵

A

为空(没有任何列),则当前局部解即为问题的一个解,返回成功;否则继续。

2. 根据一定方法选择第 c 列。如果某一列中没有 1,则返回失败,并去除当前局部解中最新加入的行。

选择第 r 行,使得

该步是非确定性的

(该步是非确定性的)。

将第 r 行加入当前局部解中。

对于满足

Ar,j=1

的每一列j,从矩阵

A2

中删除所有满足

Ai,j

的行,最后再删除第 j 列。

对所得比 A 小的新矩阵递归地执行此算法。

让我们用 X算法解决上面的精确覆盖问题。

首先,当前矩阵不为空,算法继续进行。那么先选择1最少的一列。因为 1,2,3,5,6 列都只有 2 个 1,因此我们随便选择 1 个,比如第 1 列。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值