首页 > 代码库 > POJ 3076 Sudoku (dancing links)

POJ 3076 Sudoku (dancing links)

题目大意:

16*16的数独。


思路分析:

多说无益.

想说的就是dancing links 的行是依照

第一行第一列填 1

第一行第二列填 2

……

第一行第十五列填15

第一行第二列填 1

……

第二行。。。。



列的纺织则是

第一行放1,第一行放2,。。第十六行放16.。。第一列放1.。第一列放2.。。第十六列放16.。第一块区域放1 。。。。然后在最后81位就是放自己的位置,准确的说就是 r*m+c。


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define maxn 16*16*16*16*16*4+5
#define inf 0x3f3f3f3f
using namespace std;

int n=16*16*9,m=16*16*4,p;
int map[16*16*16+5][16*16*4+5];
int L[maxn],R[maxn],D[maxn],U[maxn],S[maxn],O[maxn],col[maxn],row[maxn],head,cnt;
int num;

void dancing_links_init()
{
    head=0;
    memset(S,0,sizeof S);
    for(int i=head;i<=m;i++)
    {
        R[i]=(i+1)%(m+1);
        L[i]=(i-1+m+1)%(m+1);
        U[i]=D[i]=i;
    }
    cnt=m+1;
    for(int i=1;i<=n;i++)
    {
        int rowh=-1;
        for(int j=1;j<=m;j++)
        {
            if(map[i][j])
            {
                S[j]++;
                U[cnt]=U[j];
                D[U[j]]=cnt;
                U[j]=cnt;
                D[cnt]=j;
                row[cnt]=i;
                col[cnt]=j;
                if(rowh==-1)
                {
                    L[cnt]=R[cnt]=cnt;
                    rowh=cnt;
                }
                else
                {
                    L[cnt]=L[rowh];
                    R[L[rowh]]=cnt;
                    R[cnt]=rowh;
                    L[rowh]=cnt;
                }
                cnt++;
            }
        }
    }
}
void Remove(const 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 Resume(const int &c)
{
    for(int i=U[c];i!=c;i=U[i])
    {
        for(int j=L[i];j!=i;j=L[j])
        {
            ++S[col[j]];
            U[D[j]]=j;
            D[U[j]]=j;
        }
    }
    L[R[c]]=c;
    R[L[c]]=c;
}
bool dfs(const int &k)//可行解
{
    if(head==R[head])
    {
        sort(O,O+256);
        for(int i=0;i<256;i++)
        {
            printf("%c",O[i]-i*16+'A'-1);
            if(i%16==15)puts("");
        }
        puts("");
        return true;
    }
    int mx=inf,cur=0;
    for(int t=R[head];t!=head;t=R[t])
    {
        if(S[t]<mx)
        {
            mx=S[t];
            cur=t;
        }
    }
    Remove(cur);//依据開始的时候的推断条件,能够知道是一列一列的选择
    for(int i=D[cur];i!=cur;i=D[i])//这里就是先选择列
    {//然后去选择删除哪一行是覆盖了这列的
        O[k]=row[i];
        for(int j=R[i];j!=i;j=R[j])
        {
            Remove(col[j]);
        }
        if(dfs(k+1))return true;
        for(int j=L[i];j!=i;j=L[j])
        {
            Resume(col[j]);
        }
    }
    Resume(cur);
    return false;
}
/*
void dfs(const int &k)//最优解
{
    if(R[head]==head)
    {
        if(k<num)num=k;
        return;
    }
    if(k>=num)return;
    int mx=inf,cur=0;
    for(int t=R[head];t!=head;t=R[t])
    {
        if(S[t]<mx)
        {
            mx=S[t];
            cur=t;
        }
    }
    Remove(cur);
    for(int i=D[cur];i!=cur;i=D[i])
    {
        for(int j=R[i];j!=i;j=R[j])
        {
            Remove(col[j]);
        }
        dfs(k+1);
        for(int j=L[i];j!=i;j=L[j])
        {
            Resume(col[j]);
        }
    }
    Resume(cur);
}
*/
char tmp[16][1111];
char str[1111];
int main()
{
    while(scanf("%s",tmp[0])!=EOF)
    {
        for(int i=1;i<16;i++)scanf("%s",tmp[i]);
        int cnt=0;
        for(int i=0;i<16;i++)
        for(int j=0;j<16;j++)
        str[cnt++]=tmp[i][j];

        memset(map,0,sizeof map);
        int len=cnt;
        for(int i=0;i<len;i++)
        {
            int r=i/16;
            int c=i-r*16;
            int base=(r*16+c)*16;

            if(str[i]=='-')
            {
                for(int k=1;k<=16;k++)
                {
                    map[base+k][r*16+k]=1;
                    map[base+k][256+c*16+k]=1;
                    map[base+k][256+256+16*(4*(r/4)+(c/4))+k]=1;
                    map[base+k][256*3+r*16+c+1]=1;
                }
            }
            else
            {
                int k=str[i]-'A'+1;
                map[base+k][r*16+k]=1;
                map[base+k][256+c*16+k]=1;
                map[base+k][256+256+16*(4*(r/4)+(c/4))+k]=1;
                map[base+k][256+256+256+r*16+c+1]=1;
            }
        }
        dancing_links_init();
        dfs(0);
    }
    return 0;
}


POJ 3076 Sudoku (dancing links)