浅入 dancing links x(舞蹈链算法)

abastract:利用dancing links 解决精确覆盖问题,例如数独,n皇后问题。

要学习dacning links 算法,首先要先了解该算法所适用的问题,即精确覆盖问题,下面先了解精确覆盖问题。

精确覆盖问题

何为精确覆盖问题

  在一个全集X中若干子集的集合为S,精确覆盖(Exactcover)是指,S的子集S*,满足X中的每一个元素在S*中恰好出现一次。

定义 

  满足以下条件的集合为一个精确覆盖: 
    S*中任意两个集合没有交集,即X中的元素在S*中出现最多一次 
    S*中集合的全集为X,即X中的元素在S*中出现最少一次 
    合二为一,即X中的元素在S*中出现恰好一次。

  举例

  令={N,O,E,P}是集合X={1,2,3,4}的一个子集,并满足: 
    N={} 
    O={1,3} 
    E={2,4} 
    P={2,3}. 
    其中一个子集{O,E}是X的一个精确覆盖,因为O={1,3}而E={2,4}的并集恰好是X={1,2,3,4}。同理,{N,O,E}也是X.的一个精确覆盖。空集并不影响结论。

精确覆盖问题的表示方式

  一般的,我们用一个集合s包含s中的元素的单向关系表示精确覆盖问题。常用的有以下两种方法:

  • 矩阵表示法

  包含关系可以用一个关系矩阵表示。.矩阵每行表示S的一个子集,每列表示X中的一个元素。矩阵行列交点元素为1表示对应的元素在对应的集合中,不在则为0。

  通过这种矩阵表示法,求一个精确覆盖转化为求矩阵的若干个行的集合,使每列有且仅有一个1。同时,该问题也是精确覆盖的典型例题之一。

  下表为其中一个例子:

   

  S*={B,D,F}便是一个精确覆盖。

  • 图论表示法

  可将精确覆盖问题转化为一个二分图,左侧为集合,右侧为元素,左侧集合若与右侧元素有包含关系则连边,通过将左侧节点与其所有边保留与否求解一个右侧的每一个节点恰好有一条边的匹配。

  接下来就是dancing links x算法了。


  Dancing Links X 算法

历史

  X算法是高德纳提出的解决精确覆盖问题的算法,而dancing links X算法则是DonKnuth(《计算机程序设计艺术》的作者)提出的对X算法的一种高效实现,这种实现建立在如上所说的矩阵表示法上。

算法思想

  由如上精确覆盖问题的矩阵表示法中,我们知道dancing links x 是用来求解一个 01矩阵中选取哪几行可以使得这几行每一列都有且仅有一个1(就是每个元素在这几个子集里有且仅有出现过一次)。

  先不管他的实际意义,我们需要做的就是在一个01矩阵的选取某几行使之符合上述条件。

  我们很容易就想到枚举,然后判断符不符合条件,但是这个做法实在是太消耗时间。

  dacing links x就是一个高效的求解该类问题的算法,而这种算法,基于交叉十字循环双向链(听起来很高大上,其实就是一堆链表)的数据结构。  

  例如:如下的矩阵

  就包含了这样一个集合(第1、4、5行)

  如何利用给定的矩阵求出相应的行的集合呢?我们采用回溯法

  

  先假定选择第1行,如下所示:

  如上图中所示,红色的那行是选中的一行,这一行中有3个1,分别是第3、5、6列。

  由于这3列已经包含了1,故,把这三列往下标示,图中的蓝色部分。蓝色部分包含3个1,分别在2行中,把这2行用紫色标示出来

  根据定义,同一列的1只能有1个,故紫色的两行,和红色的一行的1相冲突。

  那么在接下来的求解中,红色的部分、蓝色的部分、紫色的部分都不能用了,把这些部分都删除,得到一个新的矩阵

  

  行分别对应矩阵1中的第2、4、5行

  列分别对应矩阵1中的第1、2、4、7列 

  于是问题就转换为一个规模小点的精确覆盖问题

  在新的矩阵中再选择第1行,如下图所示

  还是按照之前的步骤,进行标示。红色、蓝色和紫色的部分又全都删除,导致新的空矩阵产生,而红色的一行中有0(有0就说明这一列没有1覆盖)。说明,第1行选择是错误的

  那么回到之前,选择第2行,如下图所示  

  按照之前的步骤,进行标示。把红色、蓝色、紫色部分删除后,得到新的矩阵

  

  行对应矩阵2中的第3行,矩阵1中的第5行

  列对应矩阵2中的第2、4列,矩阵1中的第2、7列

   由于剩下的矩阵只有1行,且都是1,选择这一行,问题就解决

  于是该问题的解就是矩阵1中第1行、矩阵2中的第2行、矩阵3中的第1行。也就是矩阵1中的第1、4、5行()

(例子引用自http://www.cnblogs.com/grenet/p/3145800.html)

时间: 2024-10-17 11:05:40

浅入 dancing links x(舞蹈链算法)的相关文章

跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题(转)

跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题 转:http://www.cnblogs.com/grenet/p/3145800.html 精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 例如:如下的矩阵 就包含了这样一个集合(第1.4.5行) 如何利用给定的矩阵求出相应的行的集合呢?我们采用回溯法 矩阵1: 先假定选择第1行,如下所示: 如上图中所示,红色的那行是选中的一行,这一行中有3个1,分别是第3.5.

浅谈舞蹈链

舞蹈链解决精确覆盖问题 一.问题引入:有n 个人, 每个人有一些想吃的菜. 只有你给这个人所有他想吃的菜,他才会吃.可是你只有m 种菜, 每样一份.你必需把菜卖完. 问最多能满足多少人. *精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1假设有5种菜,4个人 ,1表示他喜欢吃这种菜.(1)0 1 0 1 0(2)1 0 0 0 0(3)1 1 1 0 0(4)0 0 1 0 1可见最多满足第1 .2 .4. 答案得出的过程.Step1:我们

使用修改版Dancing link X (舞蹈链)求解aquarium游戏

如果把舞蹈表的所有行的消除条件,改成覆盖总值达到n后消除,而不是覆盖总值达到1后消除,并且覆盖的行值也不是1,那会怎么样? 就变成了多值覆盖游戏!(其实这不就是舞蹈链的重复覆盖特殊情况了嘛) 正好这里有个游戏要解:https://www.puzzle-aquarium.com/里面的aquarium游戏,规则是: 1.游戏棋盘被分成几块,每块被称为一个“水箱”2.游戏中你可以给每个水箱灌一些水,也可以让它空着3.同一个水箱内的水位是等高的.也即同一水箱内的同一行的单元格,要么都有水,要么都空着.

使用改良版多值覆盖Dancing link X (舞蹈链)求解aquarium游戏

在上一篇文章中,我们通过改造了dancing link代码解出了aquarium游戏,并输出了正确答案. 但是之前的代码感觉有些慢,10*10的谜面都要跑24秒,而且感觉之前的dancing link代码有些不完善(存在重复查询问题).这一篇文章介绍如何改良多值覆盖dancing link模板代码,还有如何在整体上优化这个游戏的解题流程. 之前的代码是从所有列中选择可能性最少的列进行突破,以减少查询宽度:但是在查询过程中发现了问题:之前查询过的较高占据值的行可能会再次被查询到,从而浪费不少时间.

ZOJ 3209 Dancing Links

思路:这题挺好的,本来模板不是自己敲的嘛,理解了Dancing Links后是找了一个模板的,然后正好这题让自己加深理解了,也知道在实际中怎么建矩阵求解了. 把n*m的矩阵看成n*m个格子,像那个数独一样,作为n*m列:每一个矩形一行. 行列都建好矩阵后,就可以用舞蹈链求解了. 问题即转化为从这些行中选择最少的一部分使每一列被覆盖且仅覆盖一次. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<ios

hihoCoder #1321 : 搜索五?数独 (Dancing Links ,精确覆盖)

hiho一下第102周的题目. 原题地址:http://hihocoder.com/problemset/problem/1321 题意:输入一个9*9数独矩阵,0表示没填的空位,输出这个数独的答案. 提示已经讲解的很清楚了.稍微整理下思路.最后附AC代码. 一.Dancing Links解决精确覆盖问题.      1.精确覆盖问题         给定一个n行,m列的01矩阵.从中选择若干行使得每一列有且恰好只有一个1. 例如: 答案是选择2,3,4行. 2.DancingLinks求解精确

hdu 4069 舞蹈链

#include <cstdio> #include <iostream> #include <algorithm> #include <vector> #include <map> #include <cstring> #include <queue> using namespace std; const int maxn = 2096; const int maxnode = 10000; int wa[4] = {1

【POJ3740】Easy Finding DLX(Dancing Links)精确覆盖问题

题意:多组数据.每组数据给你几行数,要求选出当中几行,使得每一列都有且仅有一个1,询问是可不可行,或者说能不能找出来. 题解:1.暴搜.2.DLX(Dancing links). 本文写的是DLX. 算法參考白书P406或者http://www.cnblogs.com/grenet/p/3145800.html 我说一些仔细的东西,就是删除操作的形状是 | --|---- --|---- --|---- 被删除的点们之间的联系不用删,能够保留.准确地说它并非删去了这些点,而是删去这个形. 并且恢

Dancing Links 学习 AND 代码详解

今天花时间学习了下Dancing Links,其核心思想是降低在搜索中的范围,减少复杂.降低的方法就是将用链式结构构造的图中不需要的点去掉.如果回溯再恢复. 这个方法依赖的数据结构是用数组存储的十字链表L[NN],R[NN],U[NN],D[NN] 左右上下的链接 构造数据结构: head,cnt,L[NN],R[NN],U[NN],D[NN],H[NN],COL[NN],S[NN],ROW[NN] head就是头结点,cnt就是在构图时结点的编号,S[NN]是某一列上有多少个元素,COL[NN