首页 > 代码库 > POJ 3074 Sudoku(Dancing Links)

POJ 3074 Sudoku(Dancing Links)

Dancing Links是使用双向循环十字链表的数据结构通过dfs来实现解决精确覆盖问题的强有力的武器。

而数独问题可以转化为精确覆盖问题。

通过将每个限制转化为列。每个决策转化为行。

建模型:
行数为9*9*9,数独中,第i行j列放数字k的状态存储在图中第(i*9+j)*9+k行中
列数为9*9+9*9+9*9+9*9,

其中第一个9*9代表第i格是否已填满,
用第二个9*9确保每行的数字唯一且均出现一次
第三个9*9确保每列的数字唯一且出现一次
第四个9*9确保每宫的数字唯一出现1次

 

技术分享
# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi 3.1415926535
# define eps 1e-4
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
inline int Scan() {
    int x=0,f=1;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
void Out(int a) {
    if(a<0) {putchar(-); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+0);
}
const int N=9;
//Code begin...

const int MaxN=N*N*N+10, MaxM=N*N*4+10, maxnode=MaxN*4+MaxM+10;
char g[MaxN];
struct DLX{
    int n, m, size;
    int U[maxnode], D[maxnode], R[maxnode], L[maxnode], Row[maxnode], Col[maxnode];
    int H[MaxN], S[MaxM], ansd, ans[MaxN];
    void init(int _n, int _m){
        n=_n; m=_m;
        FOR(i,0,m) S[i]=0, U[i]=D[i]=i, L[i]=i-1, R[i]=i+1;
        R[m]=0; L[0]=m; size=m;
        FOR(i,1,n) H[i]=-1;
    }
    void Link(int r, int c){
        ++S[Col[++size]=c]; Row[size]=r; D[size]=D[c]; U[D[c]]=size; U[size]=c; D[c]=size;
        if (H[r]<0) H[r]=L[size]=R[size]=size;
        else R[size]=R[H[r]], L[R[H[r]]]=size, L[size]=H[r], R[H[r]]=size;
    }
    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]) U[D[j]]=U[j], D[U[j]]=D[j], --S[Col[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[Col[U[D[j]]=D[U[j]]=j]];
        L[R[c]]=R[L[c]]=c;
    }
    bool Dance(int d){
        if (R[0]==0) {
            FO(i,0,d) g[(ans[i]-1)/9]=(ans[i]-1)%9+1;
            FO(i,0,N*N) printf("%c",g[i]);
            printf("\n");
            return true;
        }
        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[d]=Row[i];
            for (int j=R[i]; j!=i; j=R[j]) remove(Col[j]);
            if (Dance(d+1)) return true;
            for (int j=L[i]; j!=i; j=L[j]) resume(Col[j]);
        }
        resume(c);
        return false;
    }
}dlx;
void place(int &r, int &c1, int &c2, int &c3, int &c4, int i, int j, int k){
    r=(i*N+j)*N+k; c1=i*N+j+1; c2=N*N+i*N+k;
    c3=N*N*2+j*N+k; c4=N*N*3+((i/3)*3+(j/3))*N+k;
}
int main ()
{
    while (~scanf("%s",g)&&strcmp(g,"end")) {
        dlx.init(N*N*N,N*N*4);
        int r, c1, c2, c3, c4;
        FO(i,0,N) FO(j,0,N) FOR(k,1,N) if (g[i*N+j]==.||g[i*N+j]==0+k) {
            place(r,c1,c2,c3,c4,i,j,k);
            dlx.Link(r,c1); dlx.Link(r,c2); dlx.Link(r,c3); dlx.Link(r,c4);
        }
        dlx.Dance(0);
    }
    return 0;
}
View Code

 

POJ 3074 Sudoku(Dancing Links)