DLX Dancing Links X Algorithm 舞蹈链 学习总结
来源:互联网 发布:淘宝图片怎么申请保护 编辑:程序博客网 时间:2024/04/25 14:56
最近练习搜索题时遇到一类题总是会看到DLX写的题解,于是决定花一些时间学一学。
它可以用来解决覆盖问题,可重复覆盖、精确覆盖。而且DLX算法是目前已知的十分不错的解决数独问题的算法(T^T我并不会),不过至少覆盖这一类问题,我可以用它来解决了。
暂时以可重复覆盖为例,因为要解决眼前的一道题→.→
是这么一类问题:有一些由整数1~n组成的集合S1,S2,S3……Sm,要求选择若干个集合,使得这些集合的并包含1~n所有的数。问最少需要选择几个集合。
例如:n = 5, S1 = {1, 2}, S2 = {3, 4, 5}, S3 = {4, 5}, S4 = {3, 5}
S1,S2 与 S1,S3,S4都是合法的选择,不过前者选择的个数少比后者要优。
我们可以用一个m×n的0 1矩阵M来描述这个问题,M[i][j]为1表示第i个集合中有j这个元素。
然后我们就可以用搜索解决问题:对于当前一个还没有被包含的元素i,枚举选哪个集合来包含它,递归、回溯得到最优解。
矩阵M是可变的——这么说比较形象,每当我们对于元素i找了第j个集合来包含它,那么我们就删除j集合所包含的所有的元素所在列以及第j行,递归,然后再恢复。
要做到删除整行以及整列,需要特殊的数据结构,Dancing Links便可以满足这个要求。它是循环十字链表,每个元素有4个指针,指向上下左右四个方向的临近元素,每个元素对应矩阵M中的“1”。由于是循环链表,所以最左端指向最右端,最右端指向最左端,上下亦然。
对于这个数据结构,删除、恢复整行、整列操作只需要操作这些指针。这也是很精髓的一部分,对于删除第c列,我们只需要把第c列每个元素i:
L[R[i]] = L[i]; R[L[i]] = R[i];
恢复:
L[R[i]] = i; R[L[i]] = i;
每一步递归都对应回溯,可以把删除恢复第i列看作两个连续的操作,所以这么做是无误的。
【有些内容转载自http://blog.csdn.net/keyboardlabourer/article/details/13015689】(写的很棒)
例如对一个6*7矩阵
用Dancing Links可以表示如下:
A~G表示的是每一列表头,和邻接表的h数组相似。而这里的h是总表头。
每个字母下的数字S表示的是这一列有多少元素,就是说,S值即在当前剩下的这些集合中,包括元素i的个数。当我们找还没有被包含的元素i的时候,选择S值最小的可以减少对集合的选择的枚举,以节省时间。
// 这份代码是以可重复覆盖为前提写的,所以删除、恢复操作显得有些不同,再加上自己yy的成分,就比较“另类”。可重复覆盖,只需要删除列,而不需要删除行,选中一行Si后,将Si所包含所有节点对应列删除即可,这样也是可以保证此行Si在之后的递归中不再被选到。删除对应列时,我仅仅删除了列头的虚拟指针,而不是真正的把一整列的指针全部改变,会节省时间,不过需要多开一个del数组记录第i列是被哪一行删除的。用空间换时间。
精确覆盖的话。。再等等吧。
struct DLX{ #define SZ 10000005 int sz, Col, Row, ans, S[1005], del[1005], row[SZ], col[SZ]; int U[SZ], D[SZ], L[SZ], R[SZ]; void init(int num) { sz = num, Col = 0, Row = num, ans = 1<<30; memset(S, 0, sizeof S); memset(U, 0, sizeof U); memset(D, 0, sizeof D); memset(L, 0, sizeof L); memset(R, 0, sizeof R); memset(del, 0, sizeof del); memset(row, 0, sizeof row); memset(col, 0, sizeof col); for(int i = 0; i <= sz; i++) { U[i] = i, D[i] = i, L[i] = i-1, R[i] = i+1, row[i] = i; } L[0] = sz, R[sz] = 0; } void add_col(bool *x) { int fir = sz; Col ++; for(int i = 1; i <= Row; i++) if(x[i]) { sz++, S[i]++; U[sz] = U[i], D[sz] = i, L[sz] = sz-1, R[sz] = sz+1, row[sz] = i, col[sz] = Col; D[U[i]] = U[i] = sz; } if(fir != sz) R[sz] = fir+1, L[fir+1] = sz; } void remove(int c) { int t = c; do { int tt = row[t]; if(!del[tt]) L[R[tt]] = L[tt], R[L[tt]] = R[tt], del[tt] = col[c]; t = R[t]; } while(t != c); } void resume(int c) { int t = c; do { int tt = row[t]; if(del[tt] == col[c]) L[R[tt]] = tt, R[L[tt]] = tt, del[tt] = 0; t = R[t]; } while(t != c); } int h() { int res = 0; /* ... */ return res; } void dfs(int sum) { if(sum + h() >= ans) return ; if(!R[0]) { ans = sum; return ;} int r, Mins = 1<<30; for(int j = R[0]; j; j = R[j]) if(S[j] < Mins) { Mins = S[j], r = j; } for(int i = D[r]; i != r; i = D[i]) { remove(i); dfs(sum + w[col[i]]); resume(i); } } void solve() { dfs(0); printf("%d", ans); }};
- DLX Dancing Links X Algorithm 舞蹈链 学习总结
- dancing links(舞蹈链)
- 舞蹈链模板 Dancing Links
- DLX舞蹈链(Dancing Links)——求解精确覆盖问题
- DLX (Dancing Links/舞蹈链)算法——求解精确覆盖问题
- 【DLX】【vijos P1345】【codevs1174】舞蹈链(Dancing Links)——数独问题
- dancing links - 舞蹈的链表
- 【Dancing Links舞蹈链】poj 3076 Sudoku
- 舞蹈链(Dancing Links)算法
- DLX模板 +解树独(Dancing Links X)精确覆盖问题
- 【算法】Dancing Links (DLX) I
- 【算法】Dancing Links (DLX) II
- 【算法】Dancing Links (DLX) I
- 【算法】Dancing Links (DLX) II
- POJ 3074,3076,2676 数独 Dancing Links舞蹈链
- dancing links X算法
- Dancing Links x
- Dancing Links X
- javascript列表
- 百度贴吧自动图片下载爬虫
- 【---重要---】 iOS:界面适配
- C++primer学习:关联容器(3)
- Python base64模块
- DLX Dancing Links X Algorithm 舞蹈链 学习总结
- [Django入门知识浅介]用Django实现动态URL
- 汇编语言 第三版 王爽 实验四
- 分布式文件系统
- POJ1930,无限循环小数变分数
- 定制一下最近一段时间的学习计划
- try捕获到的异常找来源
- 黑马程序员——JavaSE之IO流二
- 《ArcGIS Runtime SDK for Android开发笔记》——翻译:ArcGIS Runtime SDK for Android 10.2.7发布