POJ - 3076 Sudoku (舞蹈链模板)

16*16的数独题。网上已经有很多解释了,关于解法推荐博客:https://blog.csdn.net/bl0ss0m/article/details/17918705

这里用来保存舞蹈链模板!


#include <stdio.h>
using namespace std;
typedef long long ll;
const int MAXN = 16*16*16+10;
const int MAXM = 16*16*4+10;
const int MAXNODE=MAXN*MAXM+MAXM;
const int INF = 0x3f3f3f3f;

char s[20][20];
//精确匹配模板
struct DLX{

    int N,M,size;
    int U[MAXNODE],D[MAXNODE],R[MAXNODE],L[MAXNODE];
    int Row[MAXNODE],Col[MAXNODE];

    int H[MAXN],S[MAXM];

    int ansd;//答案用了多少行
    int ansh[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;
        size=M;
        for(int i=1;i<=N;i++)
            H[i]=-1;
    }

    void Link(int r,int c){
        ++S[Col[++size]=c];
        Row[size]=r;
        D[size]=D[c];
        U[D[c]]=size;
        U[size]=c;
        D[c]=size;
        if(H[r]<0){
            H[r]=L[size]=R[size]=size;
        }
        else{
            R[size]=R[H[r]];
            L[R[H[r]]]=size;
            L[size]=H[r];
            R[H[r]]=size;
        }
    }

    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[Col[j]];
            }
    }

    void resume(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 dance(int d){
        //if(ansd<d)
        //    return;

        if(R[0]==0){
            ansd=d;
            return 1;
        }

        int c=R[0];
        for(int i=R[0];i!=0;i=R[i])
            if(S[i]<S[c])
                c=i;
        remove(c);
        for(int i=D[c];i!=c;i=D[i]){
            ansh[d]=Row[i];
            for(int j=R[i];j!=i;j=R[j])
                remove(Col[j]);
            if(dance(d+1))return 1;
            for(int j=L[i];j!=i;j=L[j])
                resume(Col[j]);
        }
        resume(c);
        return false;
    }
};
DLX g;

//重复匹配模板
struct DLX_C{

    int N,M,size;
    int U[MAXNODE],D[MAXNODE],R[MAXNODE],L[MAXNODE];
    int Row[MAXNODE],Col[MAXNODE];
    int H[MAXN],S[MAXM];
    int K;
    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;
        size=M;
        for(int i=1;i<=N;i++)
            H[i]=-1;
    }

    void Link(int r,int c){
        ++S[Col[++size]=c];
        Row[size]=r;
        D[size]=D[c];
        U[D[c]]=size;
        U[size]=c;
        D[c]=size;
        if(H[r]<0){
            H[r]=L[size]=R[size]=size;
        }
        else{
            R[size]=R[H[r]];
            L[R[H[r]]]=size;
            L[size]=H[r];
            R[H[r]]=size;
        }
    }

    void remove(int c){
        for(int i=D[c];i!=c;i=D[i])
            L[R[i]]=L[i],R[L[i]]=R[i];
    }

    void resume(int c){
        for(int i=U[c];i!=c;i=U[i])
            L[R[i]]=R[L[i]]=i;
    }

    bool v[MAXNODE];
    int f()
    {
        int ret = 0;
        for(int c = R[0];c != 0;c = R[c])v[c] = true;
        for(int c = R[0];c != 0;c = R[c])
            if(v[c])
            {
                ret++;
                v[c] = false;
                for(int i = D[c];i != c;i = D[i])
                    for(int j = R[i];j != i;j = R[j])
                        v[Col[j]] = false;
            }
        return ret;

    }

    bool dance(int d)
    {
        if(d + f() > K)return false;
        if(R[0] == 0)return d <= K;

        int c = R[0];
        for(int i = R[0];i != 0;i = R[i])
            if(S[i] < S[c])
                c = i;
        for(int i = D[c];i != c;i = D[i])
        {
            remove(i);
            for(int j = R[i];j != i;j = R[j])remove(j);
            if(dance(d+1))return true;
            for(int j = L[i];j != i;j = L[j])resume(j);
            resume(i);
        }
        return false;
    }
};
//DLX_C g;

//用与数独快速求解填了是哪一个数字
int encode(int a,int b,int c)
{
    return a*256+b*16+c+1;
}
void decode(int code,int &a,int &b,int &c)
{
    code--;
    c=code%16;code/=16;
    b=code%16;code/=16;
    a=code;
}

int main(){

    bool first=true;
    while(scanf("%s",s[0])!=EOF)
    {
        if(first)first=false;
        else printf("\n");

        for(int i=1;i<16;i++)
            scanf("%s",s[i]);
        g.init(16*16*16,16*16*4);

        for(int r=0;r<16;r++)
            for(int c=0;c<16;c++)
                for(int v=0;v<16;v++)
                    if(s[r][c]=='-'||s[r][c]=='A'+v)
                    {
                        int row=encode(r,c,v);
                        g.Link(row,encode(0,r,c));
                        g.Link(row,encode(1,r,v));
                        g.Link(row,encode(2,c,v));
                        g.Link(row,encode(3,(r/4)*4+c/4,v));
                    }
        g.dance(0);
        for(int i=0;i<g.ansd;i++)
        {
            int r,c,v;
            decode(g.ansh[i],r,c,v);
            s[r][c]='A'+v;
        }
        for(int i=0;i<16;i++)
            printf("%s\n",s[i]);
    }

    return 0;
}






猜你喜欢

转载自blog.csdn.net/lzc504603913/article/details/80110321