poj 3074 Sudoku (精确覆盖,DLX,搜索)

来源:互联网 发布:许知远 陈嘉映 知乎 编辑:程序博客网 时间:2024/05/01 16:59

题意:一个9*9的数独,实现给你一些放好的数,且保证答案只有一种,让你输出答案。

思路:这题可以采用精确覆盖的DLX做法。首先对于数独而言,每个格子有9种情况,且有9*9 个格子,所以可以让行等于9*9*9。然后再看数独的限制条件,每个数字在每一行,每一列,每一个3*3的区域中只能出现一次。因此根据精确覆盖的特性,每一个元素只能被覆盖一次,可以设列为9行每行个,9列每行9个,9个小区域每行9个,且81个格子放一个,即(9+9+9)*9+81列,所以元素为(729)*(4*9*9)个。接下来直接使用DLX,注意的是对于每个元素设个X数组,值为当前元素所在行,便于输出。

代码如下:

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#define inf 0x3f3f3f3f//最大值#include <algorithm>using namespace std;const int maxnn=250000;const int N=9;const int maxr=N*N*N+10;const int maxc=N*N*4+10;char map[maxr];int size;int x[maxnn];int v[maxr];struct node{    int u,d,l,r;    int s,p;};node dlx[maxnn];//十字链表int head;int h[maxr];//行头int q[100];//答案集合,存储当前元素void init(int r,int c)//初始化{    head=0;    for(int i=0; i<=c; i++)    {        dlx[i].s=0;        dlx[i].u=i;        dlx[i].d=i;        dlx[i].r=i+1;        dlx[i+1].l=i;    }    size=c;    dlx[c].r=0;    while(r)    {        h[r--]=-1;    }}void remove(int c){    dlx[dlx[c].r].l=dlx[c].l;    dlx[dlx[c].l].r=dlx[c].r;    for(int i=dlx[c].d; i!=c; i=dlx[i].d)        for(int j=dlx[i].r; j!=i; j=dlx[j].r)        {            dlx[dlx[j].d].u=dlx[j].u;            dlx[dlx[j].u].d=dlx[j].d;            dlx[dlx[j].p].s--;        }}void resume(int c){    for(int i=dlx[c].u; i!=c; i=dlx[i].u)        for(int j=dlx[i].l; j!=i; j=dlx[j].l)        {            dlx[dlx[j].u].d=j;            dlx[dlx[j].d].u=j;            dlx[dlx[j].p].s++;        }    dlx[dlx[c].r].l=dlx[dlx[c].l].r=c;}bool dfs_dlx(int k)//DLX{    if(dlx[head].r==head)    {        for(int i=0; i<k; i++)        {            map[(x[q[i]]-1)/9+1]=(x[q[i]]-1)%9+1+'0';        }        for(int i=1; i<=N*N; i++)        {            printf("%c",map[i]);        }        printf("\n");        return true;    }    int c;    int tmp=inf;    for(int i=dlx[head].r; i!=head; i=dlx[i].r)    {        if(dlx[i].s<tmp)        {            tmp=dlx[i].s;            c=i;        }    }    //cout<<c<<endl;    remove(c);    for(int i=dlx[c].d; i!=c; i=dlx[i].d)    {        q[k]=i;        for(int j=dlx[i].r; j!=i; j=dlx[j].r)        {            remove(dlx[j].p);        }        if(dfs_dlx(k+1))        {            return true;        }        for(int j=dlx[i].l; j!=i; j=dlx[j].l)        {            resume(dlx[j].p);        }    }    resume(c);    return false;}void connect(int r,int c)//插入r行,c列{    int tmp=++size;    dlx[tmp].p=c;    dlx[c].s++;    x[tmp]=r;    dlx[tmp].d=dlx[c].d;    dlx[dlx[c].d].u=tmp;    dlx[tmp].u=c;    dlx[c].d=tmp;    if(h[r]<0)    {        h[r]=tmp;        dlx[tmp].l=tmp;        dlx[tmp].r=tmp;    }    else    {        dlx[tmp].r=dlx[h[r]].r;        dlx[dlx[h[r]].r].l=tmp;        dlx[tmp].l=h[r];        dlx[h[r]].r=tmp;    }}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(){   // freopen("in.txt","r",stdin);    int r,c1,c2,c3,c4;    while(scanf("%s",map),map[0]!='e')    {        init(maxr,4*N*N);        memset(v,0,sizeof(v));        for(int k=0,i=0; i<9; ++i)            for(int j=0; j<9; ++j,++k)            {                if(map[k]>'0'&&map[k]<='9')                {                    place(r,c1,c2,c3,c4,i,j,map[k]-'0');                    connect(r,c1);                    connect(r,c2);                    connect(r,c3);                    connect(r,c4);                    v[c1]=1;                    v[c2]=1;                    v[c3]=1;                    v[c4]=1;                }            }        for(int i=0;i<9;i++)            for(int j=0;j<9;j++)                for(int k=1;k<=9;k++)                {                    place(r,c1,c2,c3,c4,i,j,k);                    if((v[c1]||v[c2]||v[c3]||v[c4]))                    {                        continue;                    }                    connect(r,c1);                    connect(r,c2);                    connect(r,c3);                    connect(r,c4);                }        dfs_dlx(0);    }    return 0;}


原创粉丝点击