第一个模板——精确覆盖问题
题目: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; }