DLX精確覆蓋解數獨問題

來源:互聯網
上載者:User

關於Dancing Links的介紹最好仔細閱讀一下Knuth的論文,那篇翻譯的文章也不錯,這位仁兄的 部落格比較易懂http://blog.csdn.net/sunny606/article/details/7833551

通過閱讀論文主要有如下幾點體會:

1.精確覆蓋的最基本模型是:在一個01矩陣中選擇若干個行,使得沒列都包含且僅包含一個1

2.Dangcing links的邏輯與普通dfs暴力搜尋相似,但它利用四向迴圈鏈表進行了犀利的剪枝,使得當搜尋進入下一層時鏈表變得很稀疏,且結合了一些啟發函數,因此雖然複雜度理論上是指數級的,但實際速度很快,可以在一秒內處理1000*1000規模的矩陣。

3.四向迴圈鏈表將矩陣中所有1串連,當選取了某一行時,將與之矛盾的行列暫時從鏈表中刪除進入下一層搜尋,由於只是修改指標不是真正刪除,因此在搜尋失敗後能快速恢複鏈表選取下一方案。

4.關於建模:沒列代表一個限制條件,每行代表一種方案,若方案i滿足限制j,則矩陣mat[i][j]=1,因此矩陣的構造既要滿足所有限制條件,又不能漏掉可能的方案。

以解決數獨問題為例:首先看限制:每一行每一列每一個小塊中1--9都只能出現一次,且每個格子都要選取一個元素,因此有9*(9+9+9)+81個限制。

                限制:每個格子可以去所有與已有元素不矛盾的元素,每種方案都滿足四種限制。

題目:poj3074 poj 2676 poj3076 hdu 4069 hdu3909

hdu3909比較綜合,數獨的階數不確定,要判斷無解、多解、給出的矩陣是否是最小矩陣(若去掉任意一個元素後都使得矩陣有多解則稱為最小矩陣)

多解只需在dance過程中修改一下返回條件即可,找到第二個解後再返回,判斷最小矩陣只需逐個去掉矩陣中的元素判多解即可。

import java.util.Arrays;import java.util.Scanner;public class Main{    class DLX {        int maxn = 20010;        int L[] = new int[maxn], R[] = new int[maxn], D[] = new int[maxn],                U[] = new int[maxn];        int Row[] = new int[maxn], C[] = new int[maxn], S[] = new int[maxn];        // 元素x所在行列 每列元素個數        int m, id, rowid;        int ans[] = new int[maxn], cnt;        void init(int m) {            this.m = m;            mul = 0;            for (int i = 0; i <= m; i++) {                D[i] = U[i] = i;                S[i] = 0;                L[i] = i - 1;                R[i] = i + 1;            }            L[0] = m;            R[m] = 0;            id = m + 1;            cnt = rowid = 0;            mul = 0;        }        void insert(int arr[], int len) {            for (int i = 0; i < len; i++, id++) {                int x = arr[i];                C[id] = x;                Row[id] = rowid;                S[x]++;                D[id] = x;                U[id] = U[x];                D[U[x]] = id;                U[x] = id;                if (i == 0)                    L[id] = R[id] = id;                else {                    L[id] = id - 1;                    R[id] = id - i;                    L[id - i] = id;                    R[id - 1] = id;                }            }            rowid++;        }        void remove(int c) {            L[R[c]] = L[c];            R[L[c]] = R[c];            for (int i = D[c]; i != c; i = D[i])                for (int j = R[i]; j != i; j = R[j]) {                    S[C[j]]--;                    U[D[j]] = U[j];                    D[U[j]] = D[j];                }        }        void resume(int c) {            for (int i = U[c]; i != c; i = U[i])                for (int j = L[i]; j != i; j = L[j]) {                    S[C[j]]++;                    U[D[j]] = j;                    D[U[j]] = j;                }            L[R[c]] = c;            R[L[c]] = c;        }        int mul = 0;        boolean dance() {            if (R[0] == 0) {                if (++mul > 1)                    return true;                for (int i = 0; i < cnt; i++)                    res[p[ans[i]].i][p[ans[i]].j] = p[ans[i]].val;                return false;            }            int c = R[0];            for (int i = R[0]; i != 0; i = R[i])                if (S[i] < S[c])                    c = i;            remove(c);            for (int i = D[c]; i != c; i = D[i]) {                ans[cnt++] = Row[i];                for (int j = R[i]; j != i; j = R[j])                    remove(C[j]);                if (dance())                    return true;                for (int j = L[i]; j != i; j = L[j])                    resume(C[j]);                cnt--;            }            resume(c);            return false;        }    }    class plan {        int i, j, val;        plan(int i, int j, int v) {            this.j = j;            this.i = i;            val = v;        }    }    int map[][] = new int[20][20], res[][] = new int[20][20], m,            hash[] = new int[255];    char rehash[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',            'B', 'C', 'D', 'E', 'F', 'G' };    boolean flag[] = new boolean[20];    plan p[] = new plan[5010];    DLX dlx = new DLX();    Scanner scan = new Scanner(System.in);    void build(int i, int j) {        if (map[i][j] != 0) {            Arrays.fill(flag, false);            flag[map[i][j]] = true;            return;        }        Arrays.fill(flag, true);        for (int k = 1; k <= m * m; k++)            flag[map[k][j]] = flag[map[i][k]] = false;        i = (i - 1) / m * m + 1;        j = (j - 1) / m * m + 1;        for (int x = 0; x <m; x++)            for (int y = 0; y <m; y++)                flag[map[i + x][j + y]] = false;    }    int grid(int i, int j) {        return (i - 1) / m * m + (j - 1) / m + 1;    }    void init() {        int cnt = 0;        for (int i = '0'; i <= '9'; i++)            hash[i] = cnt++;        for (int i = 'A'; i <= 'G'; i++)            hash[i] = cnt++;    }    void work() {        int M = m * m;        dlx.init(M * M * 4);        int arr[] = new int[4];        int idx = 0;        for (int i = 1; i <= M; i++)            for (int j = 1; j <= M; j++) {                build(i, j);                for (int k = 1; k <= M; k++)                    if (flag[k]) {                        arr[0] = (i - 1) * M + k;// 行                        arr[1] = M * M + (j - 1) * M + k;// 列                        arr[2] = M * M * 2 + (grid(i, j) - 1) * M + k;// 塊                        arr[3] = M * M * 3 + (i - 1) * M + j;// 格子                        dlx.insert(arr, 4);                        p[idx++] = new plan(i, j, k);                    }            }        dlx.dance();    }    void run() {        init();        while (scan.hasNext()) {            m = scan.nextInt();            for (int i = 1; i <= m * m; i++) {                String s = scan.next();                for (int j = 1; j <= m * m; j++)                    map[i][j] = hash[s.charAt(j - 1)];            }            work();            if (dlx.mul == 2)                System.out.println("Multiple Solutions");            if (dlx.mul == 0)                System.out.println("No Solution");            if (dlx.mul == 1)                if (minimal()) {                    work();                    print();                } else                    System.out.println("Not Minimal");        }    }    boolean minimal() {        for (int i = 1; i <= m * m; i++)            for (int j = 1; j <= m * m; j++)                if (map[i][j] != 0) {                    int temp = map[i][j];                    map[i][j] = 0;                    work();                    map[i][j] = temp;                    if (dlx.mul == 1){                                                return false;                    }                }        return true;    }    void print() {        for (int i = 1; i <= m * m; i++) {            for (int j = 1; j <= m * m; j++)                System.out.print(rehash[res[i][j]]);            System.out.println();        }    }    public static void main(String[] args) {        new Main().run();    }}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.