数据结构 - Dancing Links
简介
Dancing Links 是用来解决精确覆盖问题和重复覆盖问题的一个数据结构,它的优势在于一旦问题被转化成精确覆盖或重复覆盖问题,那么就不需要自己想剪枝策略了,直接用 DLX 的剪枝就能达到一个优秀的效果。
DLX 使用十字双向循环链表存储,当然是用数组模拟的链表。
每列对应一个限制条件,每行对应一个选择方案,精确覆盖问题就是满足每个限制条件的同时每个限制条件只被一个选择方案满足,而重复覆盖问题就是一个限制条件可被多个选法满足。
精确覆盖问题
给定一个 N×M 的 0/1 矩阵 A,找到一个行的集合,使得这些行中,每一列都有且仅有一个数字 1。
题目链接:AcWing 1067,P4929。
精确覆盖问题中的删除操作需要使得一个点对应的列被删除掉、当前行对应的所有列被删掉。
当删除一列的时候,只更改首行哨兵结点的左右指针即可。要让这个列不被重复选中,因此需要把一列对应的所有行都删掉。只需要更改上下指针即可,无需更改左右指针,因为别的行是不包括当前这一列的。
删除某列中某行不代表被删除的行对应的所有列都会被删除,因此需要更改上下指针。
恢复每一行的时候使用每个结点的左右指针遍历,恢复每个点的上下指针。恢复列的时候只需要把哨兵结点更改正确即可。
1 |
|
重复覆盖问题
给定一个 N×M 的 0/1 矩阵 A,找到一个行的集合,使得这些行中,每一列至少包含一个数字 1。
题目链接:AcWing 2713。
重复覆盖问题中的删除操作需要使得一个点对应的列被删除掉、当前行对应的所有列被删掉。
当删除一列的时候,这个列是可以重复选中的,因此需要修改每个点的左右指针(包含哨兵结点),因为其它行也可能包含当前列。
因为包行当前行的所有列都被删了,所以这一行就不会被遍历到了。
恢复当前列的时候使用上下指针遍历,恢复每个结点的左右指针。
1 |
|
数独
填数独,没啥好说的。
题目链接:P1784。
本题可以用位运算优化的 DFS 解,这里转化成精确覆盖问题用 DLX 求解。
1 |
|
[NOIP2009] 靶形数独
小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教, Z 博士拿出了他最近发明的「靶形数独」,作为这两个孩子比试的题目。
靶形数独的方格同普通数独一样,在 9 格宽 9 格高 的大九宫格中有 9 个 3 格宽 3 格高 的小九宫格(用粗黑色线隔开的)。在这个大九宫格中,有一些数字是已知的,根据这些数字,利用逻辑推理,在其他的空格上填入 1 到 9 的数字。每个数字在每个小九宫格内不能 重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即 每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。
(图略,参考下面给出的题目链接)
上图具体的分值分布是:里面一格(黄色区域)为 10 分,黄色区域外面的一圈(红色区域)每个格子为 9 分,再外面一圈(蓝色区域)每个格子为 8 分,蓝色区域外面一圈(棕色区域)每个格子为 7 分,外面一圈(白色区域)每个格子为 6 分,如上图所示。
比赛的要求是:每个人必须完成一个给定的数独(每个给定数独可能有不同的填法),而且要争取更高的总分数。而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字的乘积的总和。
如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为 2829 。游戏规定,将以总分数的高低决出胜负。
直接套用上题代码框架来做。
1 |
|
SUDOKU
请你将一个 16×16 的数独填写完整,使得每行、每列、每个 4×4 十六宫格内字母 A∼P 均恰好出现一次。
保证每个输入只有唯一解决方案。
九宫格数独加强 PLUS PLUS 版本,但是实际上用 DLX 套上就直接出来了,和上面那个橙题的代码一样(当然这是因为我用 DLX 解了那个橙题 hhh)洛谷给这题评了个黑,但我觉得也就是紫。
1 |
|