POJ3076 Sudoku 舞蹈链 DLX

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解

题目(传送门)

题意概括

给出一个残缺的16*16数独,求解。

 

题解

DLX  +  矩阵构建  (两个传送门)

学完这个之后,再思考这一题。同样,每个位置每种取值4个信息。

数独共256个格子,每个格子都得填一个数,那么,我们要精确覆盖每一个格子,所以我们首先建立1~256列。

然后还有16行,每行1~16,每行都得精确覆盖,16行,又得建立16*16=256列;

然后还有16列,每列1~16,同理。

然后还有16个4*4的小格子,每个里面1~16,也同理。

那么总共要建立4*256=1024列。

代码

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=4100,M=1050,S=N*4+M;
struct DLX{
    int n,m,cnt;
    int x[S],y[S],L[S],R[S],U[S],D[S];
    int C[M],anscnt,ans[N];
    void init(int c){
        memset(x,0,sizeof x),memset(y,0,sizeof y);
        memset(L,0,sizeof L),memset(R,0,sizeof R);
        memset(U,0,sizeof U),memset(D,0,sizeof D);
        memset(C,0,sizeof C),memset(ans,0,sizeof ans);
        anscnt=0,m=c;
        for (int i=0;i<=m;i++)
            L[i]=i-1,R[i]=i+1,U[i]=D[i]=i;
        L[0]=m,R[m]=0,cnt=m;
    }
    void link(int i,int j){
        cnt++;
        x[cnt]=i;
        y[cnt]=j;
        L[cnt]=cnt-1;
        R[cnt]=cnt+1;
        D[cnt]=j;
        D[U[j]]=cnt;
        U[cnt]=U[j];
        U[j]=cnt;
        C[j]++;
    }
    void Delete(int k){
        L[R[k]]=L[k];
        R[L[k]]=R[k];
        for (int i=D[k];i!=k;i=D[i])
            for (int j=R[i];j!=i;j=R[j]){
                U[D[j]]=U[j];
                D[U[j]]=D[j];
                C[y[j]]--;
            }
    }
    void Reset(int k){
        L[R[k]]=k;
        R[L[k]]=k;
        for (int i=U[k];i!=k;i=U[i])
            for (int j=L[i];j!=i;j=L[j]){
                U[D[j]]=j;
                D[U[j]]=j;
                C[y[j]]++;
            }
    }
    bool solve(){
        if (R[0]==0)
            return true;
        anscnt++;
        int k=R[0];
        for (int i=R[k];i!=0;i=R[i])
            if (C[i]<C[k])
                k=i;
        Delete(k);
        for (int i=D[k];i!=k;i=D[i]){
            ans[anscnt]=x[i];
            for (int j=R[i];j!=i;j=R[j])
                Delete(y[j]);
            if (solve())
                return true;
            for (int j=L[i];j!=i;j=L[j])
                Reset(y[j]);
        }
        Reset(k);
        anscnt--;
        return false;
    }
}dlx;
int a[20][20],x[N],y[N],z[N];
char s[20];
int hash(int a,int b,int c){
    return a*256+b*16+c+1;
}
int main(){
    while (~scanf("%s",s+1)){
        for (int i=1;i<=16;i++){
            for (int j=1;j<=16;j++)
                if (s[j]=='-')
                    a[i][j]=0;
                else
                    a[i][j]=s[j]-'A'+1;
            if (i<16)
                scanf("%s",s+1);
        }
        dlx.init(1024);
        int Row=0;
        for (int i=1;i<=16;i++)
            for (int j=1;j<=16;j++){
                int st,en;
                if (a[i][j]==0)
                    st=1,en=16;
                else
                    st=en=a[i][j];
                for (int k=st;k<=en;k++){
                    Row++;
                    x[Row]=i,y[Row]=j,z[Row]=k;
                    int first=dlx.cnt+1;
                    dlx.link(Row,hash(0,i-1,j-1));
                    dlx.link(Row,hash(1,i-1,k-1));
                    dlx.link(Row,hash(2,j-1,k-1));
                    dlx.link(Row,hash(3,((i-1)/4)*4+(j-1)/4,k-1));
                    dlx.L[first]=dlx.cnt;
                    dlx.R[dlx.cnt]=first;
                }
            }
        bool found=dlx.solve();
        for (int i=1;i<=dlx.anscnt;i++)
            a[x[dlx.ans[i]]][y[dlx.ans[i]]]=z[dlx.ans[i]];
        for (int i=1;i<=16;puts(""),i++)
            for (int j=1;j<=16;j++)
                printf("%c",a[i][j]+'A'-1);
        puts("");
    }
    return 0;
}

 

posted @ 2017-08-07 22:06  zzd233  阅读(506)  评论(0编辑  收藏  举报