3074 DLX解决数独

数独的DLX构造:9*9个点每个点有9种选择,这构成了DLX的729行,每行、列、阵有限制,均为9行(/列/阵),然后每行(/列/阵)都有九种数的情况,于是就有了3*9*9列,但是因为一个位置只能选一个,所以又有9*9列,每列连接一个点的九种选数情况。

    最终有4*9*9=324列,9*9*9=729行。

具体看https://blog.csdn.net/qq_40061421/article/details/85677346

    处理:

    有些点已经有数了,但是这并不重要,我们只需要给这个点加上一个行,为它已经选的数,而不要把9种情况都加上,这样在有精确覆盖的情况下(即有解),第四部分的某列在纵向就只连接一个节点,显然这个节点是必选的,所以不会出错(当然你要是依然给这个有值节点在DLX中加9行的话,那我也没招,不要问我为什么错,好吧你不会这么傻吧?)。

    而其它没有初始值的数独点,自然就加旧行了没疑问吧?

    说一个跟空间复杂度相关的事,就是一行有且仅有4个节点,分别在行、列、阵、位置这四部分的列中,那么总节点数(不算辅助节点)就应该最多是729*4,而实际上标准数独都是有唯一解的,所以需要的节点将远远小于这个数。

    再说说时间复杂度:因为我们可以为DLX加一个优化,就是每次选一个列中节点最少的列继续DLX的过程,所以我们虽然保留了已经有值的节点,但是实际上最开始就选择了它们,而若数独有解,这也是必定选择的,所以并不会出现因为层数过多而导致回溯过度而TLE的情况,也就是说它还是很快的。
 

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int INF=0x3f3f3f3f;const int maxn=3645;//每一个格子可能有9个取值。
//所以最多有81*9行。然后243列。


int U[maxn],D[maxn],L[maxn],R[maxn],C[maxn],row[maxn];//上下左右指针。
//c[i]结点i相应的列。row[i]结点i相应的行号。


int S[350],H[800],ans[100];//S[i]为i列1的个数。

//H[i]为i行的尾指针。


int n,m,cnt,deep;
struct node
{
    int x,y,v;
} st[maxn];
char maze[150],path[150];
void init()
{
    int i;
    for(i=1;i<=800;i++)
        H[i]=-1;
    for(i=0;i<=324;i++)
    {
         S[i]=0;
         L[i+1]=i;
         R[i]=i+1;
         U[i]=D[i]=i;
    }
    R[324]=deep=0;
    cnt=325;
}
void Insert(int r,int c)
{
                        //头插法建链表
    U[cnt]=c,D[cnt]=D[c];//确定新增结点上下指针信息
    U[D[c]]=cnt,D[c]=cnt;//恢复链表信息
    if(H[r]==-1)         //确定左右指针信息
        H[r]=L[cnt]=R[cnt]=cnt;//增加头
    else
    {
        L[cnt]=H[r],R[cnt]=R[H[r]];//头插法
        L[R[H[r]]]=cnt,R[H[r]]=cnt;
    }
    S[c]++;//更新附加信息
    row[cnt]=r;
    C[cnt++]=c;
}
void Remove(int c)//移除c列。
{
    int i,j;
    R[L[c]]=R[c],L[R[c]]=L[c];
    for(i=D[c];i!=c;i=D[i])
        for(j=R[i];j!=i;j=R[j])
            D[U[j]]=D[j],U[D[j]]=U[j],S[C[j]]--;
}
void Resume(int c)//还原c列。
{
    int i,j;
    R[L[c]]=L[R[c]]=c;
    for(i=D[c];i!=c;i=D[i])
        for(j=R[i];j!=i;j=R[j])
            D[U[j]]=U[D[j]]=j,S[C[j]]++;
}
bool dfs()
{
    if(R[0]==0)
        return true;
    int i,j,c,miv=INF;
    for(i=R[0];i;i=R[i])
        if(S[i]<miv)
            miv=S[i],c=i;
    Remove(c);//处理第c列
    for(i=D[c];i!=c;i=D[i])
    {
        for(j=R[i];j!=i;j=R[j])
            Remove(C[j]);
        ans[deep++]=row[i];
        if(dfs())
            return true;
        for(j=L[i];j!=i;j=L[j])
            Resume(C[j]);
        deep--;
    }
    Resume(c);
    return false;
}
int main()
{
    int i,j,v,r,p;
    while(gets(maze))
    {
        if(maze[0]=='e')
            break;
        init();
        r=1;
        for(i=1;i<=9;i++)//每行为一个格子的一种选择。


        {
            for(j=1;j<=9;j++)
            {
                if(maze[(i-1)*9+j-1]=='.')
                {
                    for(v=1;v<=9;v++)
                    {
                        Insert(r,(i-1)*9+j);
                        Insert(r,81+(i-1)*9+v);
                        Insert(r,162+(j-1)*9+v);
                        Insert(r,243+(((i-1)/3)*3+(j+2)/3-1)*9+v);
                        st[r].x=i,st[r].y=j,st[r].v=v;
                        r++;
                    }
                }
                else
                {
                    v=maze[(i-1)*9+j-1]-'0';
                    Insert(r,(i-1)*9+j);
                    Insert(r,81+(i-1)*9+v);
                    Insert(r,162+(j-1)*9+v);
                    Insert(r,243+(((i-1)/3)*3+(j+2)/3-1)*9+v);
                    st[r].x=i,st[r].y=j,st[r].v=v;
                    r++;
                }
            }
        }
        dfs();
        for(i=0;i<deep;i++)
        {
            p=ans[i];
            path[(st[p].x-1)*9+st[p].y-1]='0'+st[p].v;
        }
        path[deep]=0;
        printf("%s\n",path);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40061421/article/details/85677641
今日推荐