Poj3074-Sudoku(数独DLX)

题意: 给出一个9*9的矩阵,有一些格子已经填了数,有一些是.代表未填。求任意一组解使得每行包含1~9,每列包含1~9,每个小矩形(3*3)包含1~9。

 

解析: 精确覆盖DLX的经典题目,每一行代表要填数的情况,列共有81*4行,第一个81行代表第i行j列放了数,第二个81列代表第i行放的数k,第三个81列

代表第j列放的数k,第四个81行代表第i个小矩形放的数k。对于字符为.的情况添加9行,对于字符为数字的情况添加一行。然后就是跑一遍DLX,保存一下答案

输出即可。

 

代码

#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int INF=1e9+7;
const int ms=81*10;
const int maxn=ms*4;
int ans[maxn];
struct DLX
{
    int n,id;
    int L[maxn],R[maxn],U[maxn],D[maxn];
    int C[maxn],S[maxn],loc[maxn][3];
    int H[ms];
    void init(int nn=0)
    {
        n=nn;
        for(int i=0;i<=n;i++) U[i]=D[i]=i,L[i]=i-1,R[i]=i+1;
        L[0]=n; R[n]=0;
        id=n;
        memset(S,0,sizeof(S));
        memset(H,-1,sizeof(H));
    }
    void Link(int x,int y,int px,int py,int k)
    {
        ++id;
        D[id]=y; U[id]=U[y];
        D[U[y]]=id; U[y]=id;
        loc[id][0]=px,loc[id][1]=py,loc[id][2]=k;
        C[id]=y; S[y]++;
        if(H[x]==-1) H[x]=L[id]=R[id]=id;
        else
        {
            int a=H[x];
            int b=R[a];
            L[id]=a; R[a]=id;
            R[id]=b; L[b]=id;
            H[x]=id;
        }
    }
    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[C[j]]--;
        }
    }
    void Resume(int c)
    {
        for(int i=U[c];i!=c;i=U[i])
            for(int j=R[i];j!=i;j=R[j])
        {
            S[C[j]]++;
            U[D[j]]=j;
            D[U[j]]=j;
        }
        L[R[c]]=c;
        R[L[c]]=c;
    }
    bool dfs(int step)
    {
        if(step==81) return true;
        if(R[0]==0) return false;
        int Min=INF,c=-1;
        for(int i=R[0];i;i=R[i])
            if(Min>S[i]){ Min=S[i]; c=i; }
        Remove(c);
        for(int i=D[c];i!=c;i=D[i])
        {
            ans[step]=i;
            for(int j=R[i];j!=i;j=R[j]) Remove(C[j]);
            if(dfs(step+1)) return true;
            for(int j=L[i];j!=i;j=L[j]) Resume(C[j]);
        }
        Resume(c);
        return false;
    }
}dlx;
int main()
{
    char S[90];
    while(scanf("%s",S)!=EOF)
    {
        if(S[0]=='e') break;
        dlx.init(81*4);
        int k=0,r=0;
        for(int x=0;x<9;x++)
            for(int y=0;y<9;y++)
        {
            char ch=S[k++];
            int a,b,c,d;
            if(ch=='.')
            {
                for(int i=1;i<=9;i++)
                {
                    a=x*9+y+1;
                    b=x*9+i+81;
                    c=y*9+i+81+81;
                    int s=(x/3)*3+y/3;
                    d=s*9+i+81+81+81;
                    ++r;
                    dlx.Link(r,a,x,y,i);
                    dlx.Link(r,b,x,y,i);
                    dlx.Link(r,c,x,y,i);
                    dlx.Link(r,d,x,y,i);
                }
            }
            else
            {
                int i=ch-'0';
                a=x*9+y+1;
                b=x*9+i+81;
                c=y*9+i+81+81;
                int s=(x/3)*3+y/3;
                d=s*9+i+81+81+81;
                ++r;
                dlx.Link(r,a,x,y,i);
                dlx.Link(r,b,x,y,i);
                dlx.Link(r,c,x,y,i);
                dlx.Link(r,d,x,y,i);
            }
        }
        dlx.dfs(0);
        int res[10][10];
        for(int i=0;i<81;i++)
        {
            int a=ans[i];
            int x=dlx.loc[a][0],y=dlx.loc[a][1],k=dlx.loc[a][2];
            res[x][y]=k;
        }
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++) printf("%d",res[i][j]);
        printf("\n");
    }
    return 0;
}
View Code

 

posted @ 2016-08-08 18:41  wust_ouyangli  阅读(538)  评论(0编辑  收藏  举报