http://www.cnblogs.com/grenet/p/3145800.html

链接给的博客写的很好,比较好懂。

可惜不是c语言...

于是决定自己要建一个模板。

一道裸题:hustoj 1017 exact cover 输入一个矩阵求选哪些行,使得这是一个精确覆盖

AC通道:http://acm.hust.edu.cn/problem/show/1017

 #include<cstdio>
#include<cstring>
#include<algorithm> using namespace std; const int maxn=;
const int INF=0x7fffffff; typedef int array[maxn];
typedef int Array[maxn*maxn]; int n,m,cnt,size;
array last,f,d,ans;
Array L,R,U,D,c,r,s; void build(){ //初始化
/*构造矩阵第一行:
1.将第一行的两端环状处理。[提示]:第一行的元素的标号就是其列的标号。
2.对于第一行的所有元素:
连接其左右;标注其行列;清空列中表示的元素个数;清空表示列的上一个元素的d数组。*/ L[]=m,R[m]=;
for(int i=;i<=m;i++){
L[i]=i-,R[i-]=i;
c[i]=i;r[i]=;
s[i]=;
d[i]=;
} //清空所有行上的表示上一个元素的last数组和表示首元素的f数组
for(int i=;i<=n;i++) last[i]=f[i]=;
} void del(int col){ //删列操作
/*
1.在第一行中删除这个列节点。
2.找到每个在这条列上的节点i
将节点i所在的行从列表中删除
*/ L[R[col]]=L[col],R[L[col]]=R[col]; //在第一行中删除这个列节点。 for(int i=D[col];i!=col;i=D[i])
for(int j=R[i];j!=i;j=R[j]) //将节点i所在的行删除干净[因为是环状的,所以可以删掉这行上的所有节点]
U[D[j]]=U[j],D[U[j]]=D[j],s[c[j]]--; //这些节点都在列表中不再被查询得到。
} void add(int col){ //恢复列操作
/*
1.在第一行中恢复这个列节点。
2.找到每个在这条列上的节点i
将节点i所在的行有顺序的从列表中恢复
*/ R[L[col]]=col,L[R[col]]=col; //因为删除时其实是间接删除[将其两边元素的指针改变],恢复只需要从它自己出发恢复两边即可。 for(int i=U[col];i!=col;i=U[i])
for(int j=L[i];j!=i;j=L[j]) //同删除的顺序相反的添加回来[即后删去的先添加],才保证了顺序,不会错
U[D[j]]=j,D[U[j]]=j,s[c[j]]++; //同删除的感觉,通过行表找到这些丢失的点,然后从它自己来恢复列表中它们的位置。
} bool search(int k){
if(R[]==){ //第一行中的所有元素都被删除[即列都被标记,完成了精确覆盖]了
printf("%d",k);
for(int i=;i<=k;i++)
printf(" %d",r[ans[i]]);
putchar('\n');
return true;
}
int Min=INF,C;
for(int i=R[];i;i=R[i])
if(Min>s[i]) Min=s[i],C=i; //优先选择列中元素少的列来处理
del(C);
for(int i=D[C];i!=C;i=D[i]){ //确定要删掉这列,但是要考虑删掉哪一行[当然是必须要与这一列相交的行]
ans[k+]=i;
for(int j=R[i];j!=i/*环状链表的好处,可以循环寻找,找到所有元素*/;j=R[j]) del(c[j]); //当确定删掉i行时,还要删掉所有与其相交的列
if(search(k+)) return true;
for(int j=L[i];j!=i;j=L[j]) /*环状链表的另一个好处,可以让添加的顺序与删除的顺序相反,从而达到后删去的先添加的形式*/
add(c[j]); //回溯过程,补充回原来删去的列。
}
add(C);
return false;
} void link(int row/*行*/,int col/*列*/){
size++; //点的数目++
s[col]++; //所在列的元素个数++ /*行操作:
如果这一行之前没有元素了,这个元素作为本行的首元素,记录在f[row]中;并记录在表示上一个元素的last[row]中。
若所在行之前还有元素,将这个元素与上一个元素连起来,更新last[];并将这个元素的右端与该行的首元素连起来,形成一个环状的结构。*/
if(!last[row])
last[row]=size,
R[size]=size,L[size]=size,
f[row]=size;
else
L[size]=last[row],R[last[row]]=size,
last[row]=size,
R[size]=f[row],L[f[row]]=size; /*列操作:
【与行操作有所不同】:我们事先已经构造出了矩阵的第一行,不存在所谓首元素,因为首元素就是这一列的标号。
如果这一列之前没有添加过元素,将当前元素与这一列的标号首尾相连,更新表示上一个元素的d[col]。
若之前添加过元素,将这个元素与上一个元素连起来;并将这个元素充当此行的末尾,与这一列的标号相连构成一个环状结构;更新d[col]。*/
if(!d[col])
U[col]=size,D[size]=col,
D[col]=size,U[size]=col,
d[col]=size; else
U[col]=size,D[size]=col,
U[size]=d[col],D[d[col]]=size,
d[col]=size; c[size]=col,r[size]=row; //处理完与其它节点的关系后,再给自己打上行列的标号
} int main(){
int k,x; while(~scanf("%d%d",&n,&m)){
build();
size=m; //前m个元素已经使用过了,不参与计数
for(int i=;i<=n;i++){
scanf("%d",&k);
while(k--)
scanf("%d",&x),link(i,x);
}
if(!search()) puts("NO");
} return ;
}

dancing link的更多相关文章

  1. Dancing Link 详解(转载)

    Dancing Link详解: http://www.cnblogs.com/grenet/p/3145800.html Dancing Link求解数独: http://www.cnblogs.co ...

  2. dancing link模板

    #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #i ...

  3. dancing link 学习资源导航+心得

    dancing link简直是求解数独的神器,NOIP2009最后一题靶形数独,DFS 各种改变搜索顺序 都没法过,最后还是用了卡时过得.用dancing link写,秒杀所有数据,总时间才400ms ...

  4. 【Dancing Link专题】解题报告

    DLX用于优化精确覆盖问题,由于普通的DFS暴力搜索会超时,DLX是一个很强有力的优化手段,其实DLX的原理很简单,就是利用十字链表的快速删除和恢复特点,在DFS时删除一些行和列以减小查找规模,使得搜 ...

  5. bzoj 2706: [SDOI2012]棋盘覆盖 Dancing Link

    2706: [SDOI2012]棋盘覆盖 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 255  Solved: 77[Submit][Status] ...

  6. hustoj 1017 - Exact cover dancing link

    1017 - Exact cover Time Limit: 15s Memory Limit: 128MB Special Judge Submissions: 5851 Solved: 3092 ...

  7. hdu 1426 Sudoku Killer ( Dancing Link 精确覆盖 )

    利用 Dancing Link 来解数独 详细的能够看    lrj 的训练指南 和 < Dancing Links 在搜索中的应用 >这篇论文 Dancing Link 来求解数独 , ...

  8. Dancing Link专题

    一些链接: http://www.cnblogs.com/-sunshine/p/3358922.html http://www.cnblogs.com/grenet/p/3145800.html 1 ...

  9. Dancing Link --- 模板题 HUST 1017 - Exact cover

    1017 - Exact cover Problem's Link:   http://acm.hust.edu.cn/problem/show/1017 Mean: 给定一个由0-1组成的矩阵,是否 ...

随机推荐

  1. [leetcode]_Merge Two Sorted Lists

    题目:合并两个有序单链表 思路:一开始想复杂了,以为必须在原链表上修改(绕来绕去还AC了,但是思路相当绕),其实没有,按照正常地合并两个数组同样的方法也对. 代码: public ListNode m ...

  2. Silverlight中动画的性能浅析

    Silverlight中提供了StoryBoard实现动画,可是StoryBoard的性能实在不敢恭维,特别是动画很大的时候,计算机的CPU和内存的狂增,如此一来性能实在太差,在默认的动画效果中动画实 ...

  3. redis的lua使用(EVALSHA)

    redis 127.0.0.1:6379> SCRIPT LOAD "local list=redis.call('KEYS', KEYS[1] .. '*') return (tab ...

  4. 用户View,五大布局

    1.LinearLayout 线性布局 android:orientation="horizontal" 制定线性布局的排列方式 水平 horizontal 垂直 vertical ...

  5. BAT命令介绍【转自Internet】

    一.简单批处理内部命令简介 1.Echo 命令 打开回显或关闭请求回显功能,或显示消息.如果没有任何参数,echo 命令将显示当前回显设置. 语法: echo [{on│off}] [message] ...

  6. 傅里叶变换 fft_generic halcon

    傅立叶变换(FT, Fourier Transform)的作用是将一个信号由时域变换到频域.其实就是把数据由横坐标时间.纵坐标采样值的波形图格式,转换为横坐标频率.纵坐标振幅(或相位)的频谱格式.变换 ...

  7. Oracle中Clob类型处理解析:ORA-01461:仅可以插入LONG列的LONG值赋值

    感谢原作者:破剑冰-Oracle中Clob类型处理解析 上一篇分析:ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值 最近为Clob字段在插入数据时发现当字符的字节数(一个半角字符一 ...

  8. jQuery学习笔记(2)

    val() 当鼠标放上去的时候,文本消失,鼠标拿开,文本恢复 效果图: code as below: <html xmlns="http://www.w3.org/1999/xhtml ...

  9. Jquery制作可以绑定的表格

    //总页数 当前页 可见页 参数 翻页执行后处理的函数 function PageTable(totalPages, currentPage, tableobj, url, where, column ...

  10. Java入门到精通——调错篇之解决MyEclipse 输入注册码后:Enter or update your subscription information.问题

    这几天,我用MyEclipse做例子的时候总是出现下面图上面的提示: 不用看就是注册码到期了要注册.找了好几个注册码总是出现Enter or update your subscription info ...