Sudoku (POJ3047)/Sudoku(ZOJ3122)

题目
POJ3047
思路
1.情况数:9 * 9 * 9 (81格,每格有9个状态)
2.条件数:每个格子是否已填写,每行,每列,每宫的数不重复(数独的规则),共9 * 9 * 4种
3.情况数对应行数,条件数对应列数,这样就能转化为精准覆盖的问题了,选择81行保证每一列有且仅有一个1.
4.行分配:每个格子有9种情况,则给每个格子分配9行,在该9行内,第x行填1,表示这个格子填了x(1~9)。那么坐标(i,j)填k,对应第(i * 9+j)* 9+k行填1,push((i * 9+j)* 9+k,满足的条件)
5.列分配:满足4个条件具体分为:
[0, 81)列 分别对应了81个格子是否被放置了数字。
[82, 2 * 81)列 分别对应了9行,每行[1, 9]个数字的放置情况;
[2 * 81, 3 * 81)列 分别对应了9列,每列[1, 9]个数字的放置情况;
[3 * 81, 4 * 81)列 分别对应了9个“宫”,每“宫”[1, 9]个数字的放置
6.4和5两点结合就可以得到:
在(i,j)位置放了k,满足条件:
(1)第i * 9+j+1格放了,push((i * 9+j) * 9+k,i * 9+j+1);
(2)第i行的k放了,push((i * 9+j) * 9+k,9 * 9+i * 9+k);
(3)第j列的k放了,push((i * 9+j) * 9+k,9 * 9 * 2+j * 9+k);
(4)第((i/3) *3+(j/3))宫的k放了,push((i * 9+j) * 9+k,9 * 9 * 3+((i/3) * 3+(j/3)) * 9+k);
每一行最多只有4个1,因为只填了一个数(只代表一个格子的状态),也有可能全为0(因为(i,j)填了k,其他的情况就都排除了,不能填)那么就不push到图中。
所以要选出81行精准覆盖所有列的1,跑一次DLX即可

#include <iostream>
#include <cstring>
using namespace std;
static const int MAXN=9*9*9+10;
static const int MAXM=9*9*4+10;
static const int MAXNODE=MAXN*4+MAXM+10;
char g[MAXN];
struct DLX{
    int n,m,siz;
    int U[MAXNODE],D[MAXNODE],L[MAXNODE],R[MAXNODE],Row[MAXNODE],Col[MAXNODE];
    int H[MAXN],S[MAXM];
    int ansd,ans[MAXN];
    void init(int _n,int _m)
    {
        n=_n;
        m=_m;
        for(int i=0;i<=m;i++)
        {
            S[i]=0;
            U[i]=D[i]=i;
            L[i]=i-1;
            R[i]=i+1;
        }
        R[m]=0;L[0]=m;
        siz=m;
        for(int i=1;i<=n;i++)
            H[i]=-1;
    }
    void push(int r,int c)
    {
        ++S[Col[++siz]=c];
        Row[siz]=r;
        D[siz]=D[c];
        U[D[c]]=siz;
        U[siz]=c;
        D[c]=siz;
        if(H[r]<0)
            H[r]=L[siz]=R[siz]=siz;
        else
        {
            R[siz]=R[H[r]];
            L[R[H[r]]]=siz;
            L[siz]=H[r];
            R[H[r]]=siz;
        }
    }
    void del(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 recover(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 dancing(int d)
    {
        if(R[0]==0)
        {
            for(int i=0;i<d;i++)
                g[(ans[i]-1)/9]=(ans[i]-1)%9+'1';
            for(int i=0;i<9*9;i++)
                cout<<g[i];
            cout<<endl;
            return true;
        }
        int c=R[0];
        for(int i=R[0];i!=0;i=R[i])
            if(S[i]<S[c])
                c=i;
        del(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])
                del(Col[j]);
            if(dancing(d+1))
                return true;
            for(int j=L[i];j!=i;j=L[j])
                recover(Col[j]);
        }
        recover(c);
        return false;
    }
};
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0),cout.tie(0);
    while(cin>>g)
    {
        if(g[0]=='e')
            break;
        DLX dlx;
        dlx.init(9*9*9,9*9*4);
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++)
                for(int k=1;k<=9;k++)
                    if(g[i*9+j]=='.' || g[i*9+j]=='0'+k)///若为.可以放置1~9,否则只能放置k
                    {
                        dlx.push((i*9+j)*9+k,i*9+j+1);
                        dlx.push((i*9+j)*9+k,9*9+i*9+k);
                        dlx.push((i*9+j)*9+k,9*9*2+j*9+k);
                        dlx.push((i*9+j)*9+k,9*9*3+((i/3)*3+(j/3))*9+k);
                    }
        dlx.dancing(0);
    }
    return 0;
}


题目
ZOJ3122
思路
同上,只是规模变大了

#include <iostream>
#include <cstring>
using namespace std;
static const int MAXN=16*16*16+10;
static const int MAXM=16*16*4+10;
static const int MAXNODE=MAXN*4+MAXM+10;
char str[MAXN];
struct DLX{
    int n,m,siz;
    int U[MAXNODE],D[MAXNODE],L[MAXNODE],R[MAXNODE],Row[MAXNODE],Col[MAXNODE];
    int H[MAXN],S[MAXM];
    int ansd,ans[MAXN];
    void init(int _n,int _m)
    {
        n=_n;
        m=_m;
        for(int i=0;i<=m;i++)
        {
            S[i]=0;
            U[i]=D[i]=i;
            L[i]=i-1;
            R[i]=i+1;
        }
        R[m]=0;L[0]=m;
        siz=m;
        for(int i=1;i<=n;i++)
            H[i]=-1;
    }
    void push(int r,int c)
    {
        ++S[Col[++siz]=c];
        Row[siz]=r;
        D[siz]=D[c];
        U[D[c]]=siz;
        U[siz]=c;
        D[c]=siz;
        if(H[r]<0)
            H[r]=L[siz]=R[siz]=siz;
        else
        {
            R[siz]=R[H[r]];
            L[R[H[r]]]=siz;
            L[siz]=H[r];
            R[H[r]]=siz;
        }
    }
    void del(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 recover(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 dancing(int d)
    {
        if(R[0]==0)
        {
            for(int i=0;i<d;i++)
                str[(ans[i]-1)/16]=(ans[i]-1)%16+'A';
            for(int i=0;i<16*16;i++)
            {
                cout<<str[i];
                if(i%16==15)cout<<endl;
            }
            return true;
        }
        int c=R[0];
        for(int i=R[0];i!=0;i=R[i])
            if(S[i]<S[c])
                c=i;
        del(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])
                del(Col[j]);
            if(dancing(d+1))
                return true;
            for(int j=L[i];j!=i;j=L[j])
                recover(Col[j]);
        }
        recover(c);
        return false;
    }
}dlx;
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0),cout.tie(0);
    int t=0;
    while(cin>>str)
    {
        if(t)
            cout<<endl;
        t++;
        for(int i=1;i<=15;i++)
            cin>>str+i*16;
        dlx.init(16*16*16,16*16*4);
        for(int i=0;i<16;i++)
            for(int j=0;j<16;j++)
                for(int k=1;k<=16;k++)
                    if(str[i*16+j]=='-' || str[i*16+j]=='A'+k-1)
                    {
                        dlx.push((i*16+j)*16+k,i*16+j+1);
                        dlx.push((i*16+j)*16+k,16*16+i*16+k);
                        dlx.push((i*16+j)*16+k,16*16*2+j*16+k);
                        dlx.push((i*16+j)*16+k,16*16*3+((i/4)*4+(j/4))*16+k);
                    }
        dlx.dancing(0);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Spidy_harker/article/details/105108072