DLX算法介绍
来源:互联网 发布:手机淘宝试衣间在哪里 编辑:程序博客网 时间:2024/04/29 12:37
在介绍DLX算法前,先说下X算法,通过比较才 知道DLX算法的好。
X算法是一种常规的回溯算法,我们可以用一个递归过程求精确覆盖问题。
递归过程描述为:选择一个没有被删除的列,然后枚举该列为1的行,将该行作为解的一部分,删除所选择的行中为1的列(在删除列时,将对应的行也删除)。用伪代码表示如下,其中A表示覆盖时的矩阵
if A is empty, the problem is solved; terminate successfully.
Otherwise choose a column, c.
Choose a row r, such that A[r,c] = 1.
Include r in the partial solution.
For each j such that A[r, j] = 1,
delete column j from matrix A;
for each i such A[i,j] = 1,
delete row i from matrix A.
Repeat this algorithm recursively on the reduced matrix A.
而DLX的妙处就是删除列,因为删除列不是一个简单的操作,还需要把它所覆盖的行也删除。DLX用到了双向循环十字链表,删除和恢复会比较高效。
删除操作主要为:
L[R[x]] = L[x];
R[L[x]] = R[x];
恢复操作为:
L[R[x]] = x;
R[L[x]] = x;
Dancing links的每个普通结点对应矩阵中的一个1,另外还有n+1个虚拟结点,其中每列上方都有一个虚拟结点,而所有虚拟结点的最前面有一个头结点h。每个结点有五个域:L,R,U,D,C,其中L表示结点的左结点,R表示结点的右结点,U表示结点的上边的结点,D表示结点的下边的结点,C表示结点所对应的列上的虚拟结点。用S[x]表示第x列上的结点个数。如下面所示:
DLX的算法用递归过程用search(k)描述如下,k初始化为0
if R[h] = h, print the current solution and return.
Otherwise choose a column object c
Cover column c
For each r = D[c], D[D[c]],...., while r <> c
set Ok = r
for each j = R[r], R[R[r]],..., while j <> r
cover column j
search(k + 1)
for each j = L[r], L[L[r]],..., while j <> r
uncover column j
uncover column c
在选择列时,选择列中元素最少的列,用伪代码描述为
c = R[h]
s = 无穷大
for each j = R[h], R[R[h]],..., while j <> h
if S[j] < s then s = s[j], c = j
在覆盖列,需要把覆盖的行也删除,伪代码为
L[R[c]] = L[c], R[L[c]] = R[c]
for i = D[c], D[D[c]], ..., while i <> c
for j = R[i], R[R[i]],..., while j <> i
U[D[j]] = U[j] D[U[j]] = D[j] S[C[j]]--
在恢复列时,伪代码为
for i = U[c], U[U[c]],...,while i <> c
for j = L[i], L[L[i]], ..., while j != i
U[D[j]] = j D[U[j]] = j S[C[j]]++
L[R[c]] = c R[L[c]] = c
DLX的模板代码如下:
class DLX{private : int n; int L[MAXN], R[MAXN], U[MAXN], D[MAXN]; int col[MAXN], row[MAXN], S[MAXN]; int ans[MAXN], ansd; int sz;public: void init(int n) { this->n = n; for (int i = 0; i <= n; i++) { L[i] = i - 1; R[i] = i + 1; U[i] = i; D[i] = i; } L[0] = n; R[n] = 0; sz = n + 1; memset(S, 0x00, sizeof(S)); } void addRow(int r, vector<int> &columns) { int first = sz; size_t size = columns.size(); for (size_t i = 0; i < size; i++) { int c = columns[i]; L[sz] = sz - 1; R[sz] = sz + 1; U[sz] = U[c]; D[U[c]] = sz; D[sz] = c; U[c] = sz; row[sz] = r; col[sz] = c; S[c]++; sz++; } L[first] = sz - 1; R[sz - 1] = first; } bool solve(vector<int> &v) { if (!dfs(0)) return false; v.clear(); for (int i = 0; i < ansd; i++) { v.push_back(ans[i]); } return true; }#define FOR(i, A, s) for (int i = A[s]; i != s; i = A[i]) void cover(int c) { L[R[c]] = L[c]; R[L[c]] = R[c]; FOR (i, D, c) { FOR (j, R, i) { S[col[j]]--; D[U[j]] = D[j]; U[D[j]] = U[j]; } } } void uncover(int c) { FOR (i, U, c) { FOR (j, L, i) { S[col[j]]++; D[U[j]] = j; U[D[j]] = j; } } R[L[c]] = c; L[R[c]] = c; } bool dfs(int dep) { if (R[0] == 0) { ansd = dep; return true; } int c = R[0]; FOR (i, S, 0) { if (S[i] < S[c]) c = i; } cover(c); FOR (i, D, c) { ans[dep] = row[i]; FOR (j, R, i) { cover(col[j]); } if (dfs(dep + 1)) return true; FOR (j, L, i) { uncover(col[j]); } } uncover(c); return false; }};
- DLX算法介绍
- DLX算法
- Sudoku DLX算法求解
- Sudoku (DLX 算法)
- 【算法】Dancing Links (DLX) I
- 【算法】Dancing Links (DLX) II
- 【精确覆盖问题】DLX算法
- 【算法】Dancing Links (DLX) I
- 【算法】Dancing Links (DLX) II
- DLX算法合集 I
- DLX算法及应用(一)DLX模板+解数独
- DLX
- DLX
- DLX
- DLX算法解数独游戏 Java版
- DLX算法求解精确覆盖问题
- (模板题)poj 3074 Sudoku(DLX算法)
- Dancing link x(DLX)算法 模板讲解
- 理解 Linux 配置文件
- POJ 3122
- 03-4. 成绩转换(15)
- DG搭建逻辑备库
- VMware Workstation 10下为Ubuntu14.04安装VMware Tools
- DLX算法介绍
- STL简介
- 【BZOJ3192】【JLOI2013】删除物品 模拟
- 04-0. 求符合给定条件的整数集(15)
- Java 注解指导手册 – 终极向导
- 啊哈C——学习2.4一起来找茬
- HintBox使用注意事项
- Android中设置控件可见与不可见详解
- [lovin'English]Once Boyfriend Upgraded to Husband