Dancing links

基本思路(Main Thoughts):

Dancing link是一种十分优美的数据结构。

通常配合IDA*,二分等方法解决可以转化为精确覆盖和重复覆盖的题目。

精确覆盖:在一个01矩阵中选几行,使得这几行组合起来的矩阵每列有且只有一个1

重复覆盖:每列可以有多个1



实现步骤(Implementation Steps):

如果是正常的搜索

解决步骤:

  1. 选最左边第一个没有被删除的列
  2. 选择一个在1中选出的列中有1的行,其他行直接删除
  3. 删掉2中选出的行剩余的元素所在的列
  4. 重复1,直到有一次没有可选列
  5. 如果一列没有被删除且列中已经没有元素,则回溯重新选择一行

  DLX基本上用到的就是这种思想

辅助数组:

R,L,U,D代表当前元素在链表中右左上下的元素

C代表i点所在列

    S代表i列元素个数

F,last,Last用于建表,分别是i行第一个元素,i行上一个元素,i列上一个元素。

  执行步骤:

    1、Dancing函数的入口

    2、判断Head.Right=Head?,若是,输出答案,返回True,退出函数。

    3、获得Head.Right的元素C

    4、标示元素C

    5、获得元素C所在列的一个元素

    6、标示该元素同行的其余元素所在的列首元素

    7、获得一个简化的问题,递归调用Daning函数,若返回的True,则返回True,退出函数。

    8、若返回的是False,则回标该元素同行的其余元素所在的列首元素,回标的顺序和之前标示的顺序相反

    9、获得元素C所在列的下一个元素,若有,跳转到步骤6

    10、若没有,回标元素C,返回False,退出函数。

  由于篇幅有限,在此贴出大神blog : http://www.cnblogs.com/grenet/p/3145800.html

  以供大家参考。

模板(Code):

 1 void build()
 2 {
 3     L[0]=m,R[m]=0;
 4     for(int i=1;i<=m;i++)
 5     {
 6         R[i-1]=i;
 7         L[i]=i-1;
 8         c[i]=0,r[i]=i;
 9         s[i]=0;d[i]=f[i]=last[i]=0;
10     }
11 }
12
13 void del(int CC)
14 {
15     L[R[CC]]=L[CC],R[L[CC]]=R[CC];
16     for(int i=D[CC];i!=CC;i=D[i])
17     for(int j=R[i];j!=i;j=R[j])
18         U[D[j]]=U[j],D[U[j]]=D[j],s[c[j]]--;
19 }
20
21 void add(int CC)
22 {
23     R[L[CC]]=CC,L[R[CC]]=CC;
24     for(int i=U[CC];i!=CC;i=U[i])
25     for(int j=L[i];j!=i;j=L[j])
26         U[D[j]]=j,D[U[j]]=j,s[c[j]]++;
27 }
28
29 bool search(int k)
30 {
31     if(R[0]==0)
32     {
33         printf("%d",k);
34         for(int i=1;i<=k;i++)
35             printf(" %d",r[ans[i]]);
36         printf("\n");
37         return 1;
38     }
39     int mn=999999,C;
40     for(int i=R[0];i;i=R[i])
41         if(mn>s[i])mn=s[i],C=i;
42     del(C);
43     for(int i=D[C];i!=C;i=D[i])
44     {
45         ans[k+1]=i;
46         for(int j=R[i];j!=i;j=R[j])del(c[j]);
47         if(search(k+1))return 1;
48         for(int j=L[i];j!=i;j=L[j])add(c[j]);
49     }
50     add(C);
51     return 0;
52 }
53
54 void link(int row,int col)
55 {
56     size++;
57     s[col]++;
58             if(!last[row])last[row]=size,R[size]=size,L[size]=size,f[row]=size;
59     else L[size]=last[row],R[last[row]]=size,last[row]=size,R[size]=f[row],L[f[row]]=size;
60     if(!d[col])d[col]=size,D[col]=size,U[size]=col,U[col]=size,D[size]=col;
61     else U[col]=size,D[size]=col,U[size]=d[col],D[d[col]]=size,d[col]=size;
62     r[size]=row,c[size]=col;
63 }    

时间&空间复杂度(Time & Memory Complexity):

空间:O(?)

时间:O(?)

主要用途&优缺点(Main Applications & Advantages & Disadvantages):

  主要用途: 通常配合IDA*,二分等方法解决可以转化为精确覆盖和重复覆盖的题目。

优点:快

缺点:长

推荐题目&数据(Recommendatory Problems & Data) :

Hustoj 1017 裸的精确覆盖

UVA 1603 破坏正方形 DLX重复覆盖

时间: 2024-12-21 21:06:52

Dancing links的相关文章

HDU 3335 Divisibility dancing links 重复覆盖

分析: dlx重复覆盖的巧用,重复覆盖的原理恰好符合本题的筛选方式,即选择一个数后,该数的倍数或约数可以保证在之后的搜索中不会被选择 于是修改一下启发函数,求解最大的重复覆盖即可. 其实不一定不被选择,只是选择以后,要么达不成目标,要不达到目标,也不如不选择更优 举下面的例子 3 2 3 6 答案一看就是 2 初始的dancing links的表示是这样的 2   3   6 2    1   0   1 3    0   1   1 6    1   1   1 然后肯定先选第一列进行删 删

HUST 1017 - Exact cover (Dancing Links 模板题)

1017 - Exact cover 时间限制:15秒 内存限制:128兆 自定评测 5584 次提交 2975 次通过 题目描述 There is an N*M matrix with only 0s and 1s, (1 <= N,M <= 1000). An exact cover is a selection of rows such that every column has a 1 in exactly one of the selected rows. Try to find o

bzoj1501: [NOI2005]智慧珠游戏 dancing links

精确覆盖问题,用dancing links求解. 打常量表比较麻烦. #include<bits/stdc++.h> #define FOR(i,s,t)for(node* i=(s)->t;i!=(s);i=i->t) const int f[60][12]={ {0,3,0,0,0,1,1,0}, {0,3,0,0,0,1,1,1}, {0,3,0,0,1,0,1,1}, {0,3,0,1,1,0,1,1}, {1,4,0,0,0,1,0,2,0,3}, {1,4,0,0,1,

HDU5046 Airport dancing links 重复覆盖+二分

这一道题和HDU2295是一样 是一个dancing links重复覆盖解决最小支配集的问题 在给定长度下求一个最小支配集,只要小于k就行 然后就是二分答案,每次求最小支配集 只不过HDU2295是浮点,这里是整数 我写的一个比较暴力 #include<cstdio> #include<cstring> #include<queue> #include<cstdlib> #include<algorithm> #include<vector

hust 1017 dancing links 精确覆盖模板题

最基础的dancing links的精确覆盖题目 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 6 using namespace std; 7 #define N 1005 8 #define MAXN 1000100 9 10 struct DLX{ 11 int n , m , size;//size表示当前dlx表中有多少

ZOJ 3209 Treasure Map (Dancing Links 精确覆盖 )

题意 :  给你一个大小为 n * m 的矩形 , 坐标是( 0 , 0 ) ~ ( n , m )  .然后给你 p 个小矩形 , 坐标是( x1 , y1 ) ~ ( x2 , y2 ) , 你选择最小的几个矩形 , 使得这些矩形可以覆盖整个矩形 , 并且互相不会重叠 .( n , m <= 30 ) 思路 : Dancing Links 的精确覆盖问题 . 我们将 n * m 的矩形分成 n * m 个小正方形 ,那么我们只要保证每个小正方形被覆盖且只被覆盖一次即可 . 那么列表示每个小正

ZOJ 3209 Dancing Links

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

ZOJ 3209 Treasure Map (Dancing Links)

Treasure Map Time Limit: 2 Seconds      Memory Limit: 32768 KB Your boss once had got many copies of a treasure map. Unfortunately, all the copies are now broken to many rectangular pieces, and what make it worse, he has lost some of the pieces. Luck

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

abastract:利用dancing links 解决精确覆盖问题,例如数独,n皇后问题. 要学习dacning links 算法,首先要先了解该算法所适用的问题,即精确覆盖问题,下面先了解精确覆盖问题. 精确覆盖问题 何为精确覆盖问题 在一个全集X中若干子集的集合为S,精确覆盖(Exactcover)是指,S的子集S*,满足X中的每一个元素在S*中恰好出现一次. 定义 满足以下条件的集合为一个精确覆盖:  S*中任意两个集合没有交集,即X中的元素在S*中出现最多一次  S*中集合的全集为X,

HDU 1426 dancing links解决数独问题

题目大意: 这是一个最简单的数独填充题目,题目保证只能产生一种数独,所以这里的初始9宫格较为稠密,可以直接dfs也没有问题 但最近练习dancing links,这类数据结构解决数独无疑效率会高很多 dancing links的数独限制条件是: 1.每行有9个元素,共9行 对应dlx81列 2.每列有9个元素,共9行 对应dlx81列 3.每个九宫格有9个元素,共9行 对应dlx81列 4.81个格子,每个格子最多有一个数 1 #include <iostream> 2 #include &l