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;    }};


0 0
原创粉丝点击