[置顶] 我的跳舞链 Dancing Links 模板

第一个模板——精确覆盖问题

题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3038

为什么选择这题呢,因为它既可以当作数独模板又能当成DLX模板,不是一举两得吗^ ^

#include<cstdio>
using namespace std;
const int N=16;
const int mm=N*N*N*4+N*N*4+N;
const int mn=N*N*N+N;
int U[mm],D[mm],L[mm],R[mm],C[mm],X[mm];
int H[mn],S[mn],Q[mn];
bool v[mn];
char map[mn];
int size;
void prepare(int r,int c)
{
    for(int i=0;i<=c;++i)
    {
        S[i]=0;
        U[i]=D[i]=i;
        L[i+1]=i;
        R[i]=i+1;
    }
    R[size=c]=0;
    while(r)H[r--]=-1;
}
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[C[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[C[U[D[j]]=D[U[j]]=j]];
    L[R[c]]=R[L[c]]=c;
}
bool Dance(int k)
{
    if(!R[0])
    {
        for(int i=0;i<k;++i)map[(X[Q[i]]-1)/N+1]=(X[Q[i]]-1)%N+'A';
        for(int i=1;i<=N*N;++i)
        {
            putchar(map[i]);
            if((i%N)==0)puts("");
        }
        return 1;
    }
    int i,j,c,tmp=mm;
    for(i=R[0];i;i=R[i])
        if(S[i]<tmp)tmp=S[c=i];
    remove(c);
    for(i=D[c];i!=c;i=D[i])
    {
        Q[k]=i;
        for(j=R[i];j!=i;j=R[j])remove(C[j]);
        if(Dance(k+1))return 1;
        for(j=L[i];j!=i;j=L[j])resume(C[j]);
    }
    resume(c);
    return 0;
}
void Link(int r,int c)
{
    ++S[C[++size]=c];
    X[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 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/4)*4+(j/4))*N+k;
}
bool init()
{
    char c;
    while(((c=getchar())<'A'||c>'P')&&c!='-'&&c!=EOF);
    if(c==EOF)return 0;
    for(int i=0;i<N*N;++i)
    {
        if(i)while(((c=getchar())<'A'||c>'P')&&c!='-');
        map[i]=c;
    }
    return 1;
}
int main()
{
    int i,j,k,r,c1,c2,c3,c4,T=0;
    while(init())
    {
        if(T++)puts("");
        prepare(mn,N*N*4);
        for(i=1;i<=mn;++i)v[i]=0;
        for(k=i=0;i<N;++i)
            for(j=0;j<N;++j,++k)
            if(map[k]!='-')
            {
                place(r,c1,c2,c3,c4,i,j,map[k]-'A'+1);
                Link(r,c1),Link(r,c2),Link(r,c3),Link(r,c4);
                v[c2]=v[c3]=v[c4]=1;
            }
        for(i=0;i<N;++i)
            for(j=0;j<N;++j)
                for(k=1;k<=N;++k)
                {
                    place(r,c1,c2,c3,c4,i,j,k);
                    if(v[c2]||v[c3]||v[c4])continue;
                    Link(r,c1),Link(r,c2),Link(r,c3),Link(r,c4);
                }
        Dance(0);
    }
    return 0;
}

第二个模板——重复覆盖问题

题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=31

#include<cstdio>
#include<cstring>
#define mm 111111
#define mn 1111
int U[mm],D[mm],L[mm],R[mm],C[mm];
int H[mn],S[mn],g[mn][mn],q[mn];
bool v[mn],x[mn],e[mn][mn];
int n,m,size,ans,r;
void prepare(int r,int c)
{
    for(int i=0;i<=c;++i)
    {
        S[i]=0;
        U[i]=D[i]=i;
        L[i+1]=i;
        R[i]=i+1;
    }
    R[c]=0;
    while(r)H[r--]=-1;
}
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;
}
int f()
{
    int i,j,c,ret=0;
    for(c=R[0];c;c=R[c])v[c]=1;
    for(c=R[0];c;c=R[c])
        if(v[c])for(v[c]=0,++ret,i=D[c];i!=c;i=D[i])
            for(j=R[i];j!=i;j=R[j])v[C[j]]=0;
    return ret;
}
void Dance(int k)
{
    if(k+f()>=ans)return;
    if(!R[0])
    {
        ans=k;
        return;
    }
    int i,j,c,tmp=mm;
    for(i=R[0];i;i=R[i])
        if(S[i]<tmp)tmp=S[c=i];
    for(i=D[c];i!=c;i=D[i])
    {
        remove(i);
        for(j=R[i];j!=i;j=R[j])remove(j);
        Dance(k+1);
        for(j=L[i];j!=i;j=L[j])resume(j);
        resume(i);
    }
}
void Link(int r,int c)
{
    ++S[C[++size]=c];
    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;
    }
}
bool ok(int x1,int y1,int x2,int y2)
{
    int i,j,id;
    r=0;
    for(i=x1;i<=x2;++i)
    {
        if(x[id=g[i<<1][(y1<<1)-1]])q[r++]=id;
        else return 0;
        if(x[id=g[i<<1][(y2<<1)+1]])q[r++]=id;
        else return 0;
    }
    for(j=y1;j<=y2;++j)
    {
        if(x[id=g[(x1<<1)-1][j<<1]])q[r++]=id;
        else return 0;
        if(x[id=g[(x2<<1)+1][j<<1]])q[r++]=id;
        else return 0;
    }
    return 1;
}
int main()
{
    int i,j,k,T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        m=n*(n+1)*2;
        for(i=0;i<=m;++i)x[i]=1;
        for(k=0,i=1;i<=n+1;++i)
        {
            for(j=1;j<=n;++j)g[i*2-1][j*2]=++k;
            for(j=1;j<=n+1;++j)g[i*2][j*2-1]=++k;
        }
        scanf("%d",&k);
        while(k--)scanf("%d",&i),x[i]=0;
        memset(e,0,sizeof(e));
        for(size=k=0;k<n;++k)
            for(i=1;i+k<=n;++i)
                for(j=1;j+k<=n;++j)
                    if(ok(i,j,i+k,j+k))
                    {
                        ++size;
                        while(r--)e[q[r]][size]=1;
                    }
        prepare(m,size);
        for(i=1;i<=m;++i)
            for(j=1;j<=size;++j)
                if(e[i][j])Link(i,j);
        ans=m;
        Dance(0);
        printf("%d\n",ans);
    }
    return 0;
}

由于的大连赛的到来,DLX的题就做到这了,希望这次能稳定发挥。。。DLX真实神奇阿!!!


你可能感兴趣的:(c)