POJ 3076 Sudoku (DLX)

16*16 的數獨,DLX的最愛。想了一會兒空着的列要不要刪掉,突然發現其實隨它搜就好了,隻影響深度不影響寬度。或者手動刪除一下也沒有大礙。

/* Created Time: Thursday, November 21, 2013 PM08:36:56 CST */
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 20;
const int MAXC = 4*256+7, MAXNODE = 4*256*16*16+7, MAXR = 16*16+7;
struct DLX {
    
    int S[MAXC];                                        // 列節點數
    int n,sz;                                           // 列數,節點數
    int L[MAXNODE],R[MAXNODE],U[MAXNODE],D[MAXNODE];    // 十字鏈表
    int ans[MAXR],ansd;                                 // 解
    int row[MAXNODE],col[MAXNODE];                      // 對應的行列號

    void init(int num) {
        n = num;
        for (int i = 0; i <= n; i ++) {
            U[i] = i; D[i] = i; L[i] = i-1; R[i] = i+1;
        }
        L[0] = n; R[n] = 0;
        sz = n+1;
        memset(S,0,sizeof(S));
    }

    void add_raw(int r,vector <int> line) {
        int first = sz;
        for (int i = 0; i < line.size(); i ++) {
            int c = line[i];
            L[sz] = sz-1; R[sz] = sz+1; U[sz] = U[c]; D[sz] = c;
            D[U[c]] = sz; U[c] = sz;
            row[sz] = r; col[sz] = c;
            S[c] ++; sz ++;
        }
        R[sz-1] = first; L[first] = sz-1;
    }

#define FOR(i,A,s) for (int i = A[s]; i != s; i = A[i])

    void remove(int c) {
        L[R[c]] = L[c];
        R[L[c]] = R[c];
        FOR(i,D,c) FOR(j,R,i) {
                U[D[j]] = U[j]; D[U[j]] = D[j]; S[col[j]] --;
            }
    }

    void restore(int c) {
        FOR(i,U,c) FOR(j,L,i) {
            U[D[j]] = j; D[U[j]] = j; S[col[j]] ++;
        }
        L[R[c]] = c;
        R[L[c]] = c;
    }

    bool dfs(int dep) {
        if (R[0]==0) {
            ansd = dep;
            return true;
        }

        int c = R[0];
        FOR(i,R,0)
            if (S[i]<S[c]) c = i;

        remove(c);
        FOR(i,D,c) {
            ans[dep] = row[i];
            FOR(j,R,i) remove(col[j]);
            if (dfs(dep+1)) return true;
            FOR(j,L,i) restore(col[j]);
        }
        restore(c);

        return false;
    }

    bool solve(vector <int> &v) {
        v.clear();
        if (!dfs(0)) return false;
        for (int i = 0; i < ansd; i ++) v.push_back(ans[i]);
        return true;
    }
};

/*******************************************************************/

DLX solver;
char mat[N][N];
int encode(int a,int b,int c) { return (a*16+b)*16+c+1; }
void decode(int v,int &a,int &b,int &c) {
    v --;
    c = v%16; v /= 16;
    b = v%16; v /= 16;
    a = v;
}
int get_b(int x,int y) { return x/4*4+y/4; }
const int POS = 0,ROW = 1,COL = 2,BLO = 3;
void get(int x,int y) {
    int b = get_b(x,y);
    for (int i = 0; i < 16; i ++)
    {
        if (mat[x][y]!='-' && mat[x][y]!=i+'A') continue;

        vector <int> v;
        v.push_back(encode(POS,x,y));
        v.push_back(encode(ROW,x,i));
        v.push_back(encode(COL,y,i));
        v.push_back(encode(BLO,b,i));

        solver.add_raw(encode(x,y,i),v);
    }
}
void work() {
    solver.init(4*256);

    for (int i = 0; i < 16; i ++) for (int j = 0; j < 16; j ++)
        get(i,j);
    
    vector <int> v;
    solver.solve(v);
    for (int i = 0; i < v.size(); i ++)
    {
        int a,b,c;
        decode(v[i],a,b,c);
        mat[a][b] = c+'A';
    }
    for (int i = 0; i < 16; i ++) puts(mat[i]);
}
int main() {
    bool first = true;
    while (~scanf("%s",mat[0])) {
        for (int i = 1; i < 16; i ++) scanf("%s",mat[i]);
        if (first) first = false; else puts("");
        work();
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章