BZOJ1501 [NOI2005]智慧珠游戏
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目(传送门)
题解
对于这一题,矩阵的构建和数独有比较大的不同,常量表也打了很长。
我们要精确覆盖的信息有两种:
1. 每种形状限用一次
2. 每个格子限填一次
然后对于每个位置的每种形状的每个形态,建立相应的行即可。
常量表贼长。
我这样打,虽然比较长,但是有助于找茬。
代码
#include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> using namespace std; const int z[12]={4,2,8,1,4,8,4,8,8,1,4,8}; const int p[12][8][4][4]={ //A { { {1,1,0,0}, {1,0,0,0}, {0,0,0,0}, {0,0,0,0} }, { {1,0,0,0}, {1,1,0,0}, {0,0,0,0}, {0,0,0,0} }, { {1,1,0,0}, {0,1,0,0}, {0,0,0,0}, {0,0,0,0} }, { {0,1,0,0}, {1,1,0,0}, {0,0,0,0}, {0,0,0,0} } }, //B { { {1,1,1,1}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0} }, { {1,0,0,0}, {1,0,0,0}, {1,0,0,0}, {1,0,0,0} } }, //C { { {1,0,0,0},//1 {1,1,1,0}, {0,0,0,0}, {0,0,0,0} }, { {1,1,1,0},//2 {1,0,0,0}, {0,0,0,0}, {0,0,0,0} }, { {0,0,1,0},//3 {1,1,1,0}, {0,0,0,0}, {0,0,0,0} }, { {1,1,1,0},//4 {0,0,1,0}, {0,0,0,0}, {0,0,0,0} }, { {1,0,0,0},//5 {1,0,0,0}, {1,1,0,0}, {0,0,0,0} }, { {1,1,0,0},//6 {1,0,0,0}, {1,0,0,0}, {0,0,0,0} }, { {0,1,0,0},//7 {0,1,0,0}, {1,1,0,0}, {0,0,0,0} }, { {1,1,0,0},//8 {0,1,0,0}, {0,1,0,0}, {0,0,0,0} } }, //D { { {1,1,0,0},//1 {1,1,0,0}, {0,0,0,0}, {0,0,0,0} } }, //E { { {1,1,1,0},//1 {1,0,0,0}, {1,0,0,0}, {0,0,0,0} }, { {1,0,0,0},//2 {1,0,0,0}, {1,1,1,0}, {0,0,0,0} }, { {1,1,1,0},//3 {0,0,1,0}, {0,0,1,0}, {0,0,0,0} }, { {0,0,1,0},//4 {0,0,1,0}, {1,1,1,0}, {0,0,0,0} } }, //F { { {1,1,1,1},//1 {0,1,0,0}, {0,0,0,0}, {0,0,0,0} }, { {1,1,1,1},//2 {0,0,1,0}, {0,0,0,0}, {0,0,0,0} }, { {0,1,0,0},//3 {1,1,1,1}, {0,0,0,0}, {0,0,0,0} }, { {0,0,1,0},//4 {1,1,1,1}, {0,0,0,0}, {0,0,0,0} }, { {1,0,0,0},//5 {1,1,0,0}, {1,0,0,0}, {1,0,0,0} }, { {1,0,0,0},//6 {1,0,0,0}, {1,1,0,0}, {1,0,0,0} }, { {0,1,0,0},//7 {1,1,0,0}, {0,1,0,0}, {0,1,0,0} }, { {0,1,0,0},//8 {0,1,0,0}, {1,1,0,0}, {0,1,0,0} } }, //G { { {1,1,1,0},//1 {1,0,1,0}, {0,0,0,0}, {0,0,0,0} }, { {1,0,1,0},//2 {1,1,1,0}, {0,0,0,0}, {0,0,0,0} }, { {1,1,0,0},//3 {1,0,0,0}, {1,1,0,0}, {0,0,0,0} }, { {1,1,0,0},//4 {0,1,0,0}, {1,1,0,0}, {0,0,0,0} } }, //H { { {1,1,1,0},//1 {1,1,0,0}, {0,0,0,0}, {0,0,0,0} }, { {1,1,1,0},//2 {0,1,1,0}, {0,0,0,0}, {0,0,0,0} }, { {1,1,0,0},//3 {1,1,1,0}, {0,0,0,0}, {0,0,0,0} }, { {0,1,1,0},//4 {1,1,1,0}, {0,0,0,0}, {0,0,0,0} }, { {1,1,0,0},//5 {1,1,0,0}, {1,0,0,0}, {0,0,0,0} }, { {1,0,0,0},//6 {1,1,0,0}, {1,1,0,0}, {0,0,0,0} }, { {0,1,0,0},//7 {1,1,0,0}, {1,1,0,0}, {0,0,0,0} }, { {1,1,0,0},//8 {1,1,0,0}, {0,1,0,0}, {0,0,0,0} } }, //I { { {1,1,1,0},//1 {0,0,1,1}, {0,0,0,0}, {0,0,0,0} }, { {0,0,1,1},//2 {1,1,1,0}, {0,0,0,0}, {0,0,0,0} }, { {0,1,1,1},//3 {1,1,0,0}, {0,0,0,0}, {0,0,0,0} }, { {1,1,0,0},//4 {0,1,1,1}, {0,0,0,0}, {0,0,0,0} }, { {1,0,0,0},//5 {1,0,0,0}, {1,1,0,0}, {0,1,0,0} }, { {0,1,0,0},//6 {1,1,0,0}, {1,0,0,0}, {1,0,0,0} }, { {1,0,0,0},//7 {1,1,0,0}, {0,1,0,0}, {0,1,0,0} }, { {0,1,0,0},//8 {0,1,0,0}, {1,1,0,0}, {1,0,0,0} } }, //J { { {0,1,0,0}, {1,1,1,0}, {0,1,0,0}, {0,0,0,0} } }, //K { { {1,0,0,0},//1 {1,1,0,0}, {0,1,1,0}, {0,0,0,0} }, { {1,1,0,0},//2 {0,1,1,0}, {0,0,1,0}, {0,0,0,0} }, { {0,1,1,0},//3 {1,1,0,0}, {1,0,0,0}, {0,0,0,0} }, { {0,0,1,0},//4 {0,1,1,0}, {1,1,0,0}, {0,0,0,0} } }, //L { { {1,1,1,1},//1 {0,0,0,1}, {0,0,0,0}, {0,0,0,0} }, { {1,1,1,1},//2 {1,0,0,0}, {0,0,0,0}, {0,0,0,0} }, { {1,0,0,0},//3 {1,1,1,1}, {0,0,0,0}, {0,0,0,0} }, { {0,0,0,1},//4 {1,1,1,1}, {0,0,0,0}, {0,0,0,0} }, { {1,0,0,0},//5 {1,0,0,0}, {1,0,0,0}, {1,1,0,0} }, { {1,1,0,0},//6 {1,0,0,0}, {1,0,0,0}, {1,0,0,0} }, { {1,1,0,0},//7 {0,1,0,0}, {0,1,0,0}, {0,1,0,0} }, { {0,1,0,0},//8 {0,1,0,0}, {0,1,0,0}, {1,1,0,0} } } }; /**********************************************************/ const int N=4000,M=100,S=N*7+M; //构建矩阵: 每个格子一个,每个形状一个 struct DLX{ int n,m,cnt; int x[S],y[S],L[S],R[S],U[S],D[S]; int C[M],anscnt,ans[N]; void init(int c){ memset(x,0,sizeof x),memset(y,0,sizeof y); memset(L,0,sizeof L),memset(R,0,sizeof R); memset(U,0,sizeof U),memset(D,0,sizeof D); memset(C,0,sizeof C),memset(ans,0,sizeof ans); anscnt=0,m=c; for (int i=0;i<=m;i++) L[i]=i-1,R[i]=i+1,U[i]=D[i]=i; L[0]=m,R[m]=0,cnt=m; } void link(int i,int j){ cnt++; x[cnt]=i; y[cnt]=j; L[cnt]=cnt-1; R[cnt]=cnt+1; D[cnt]=j; D[U[j]]=cnt; U[cnt]=U[j]; U[j]=cnt; C[j]++; } void Delete(int k){ L[R[k]]=L[k]; R[L[k]]=R[k]; for (int i=D[k];i!=k;i=D[i]) for (int j=R[i];j!=i;j=R[j]){ U[D[j]]=U[j]; D[U[j]]=D[j]; C[y[j]]--; } } void Reset(int k){ L[R[k]]=k; R[L[k]]=k; for (int i=U[k];i!=k;i=U[i]) for (int j=L[i];j!=i;j=L[j]){ U[D[j]]=j; D[U[j]]=j; C[y[j]]++; } } bool solve(){ if (R[0]==0) return true; anscnt++; int k=R[0]; for (int i=R[k];i!=0;i=R[i]) if (C[i]<C[k]) k=i; Delete(k); for (int i=D[k];i!=k;i=D[i]){ ans[anscnt]=x[i]; for (int j=R[i];j!=i;j=R[j]) Delete(y[j]); if (solve()) return true; for (int j=L[i];j!=i;j=L[j]) Reset(y[j]); } Reset(k); anscnt--; return false; } }dlx; const int L=15,n=10; int Row; char ch[L][L]; bool matched[12]; struct PIC{ int x,y,i,j; }built[N]; bool match(int x,int y,int i,int j){ char CHAR=i+'A'; for (int a=0;a<4;a++) for (int b=0;b<4;b++) if (p[i][j][a][b]&&(x+a>n||y+b>x+a||ch[x+a][y+b]!=CHAR)) return 0; return 1; } bool nmatch(int x,int y,int i,int j){ for (int a=0;a<4;a++) for (int b=0;b<4;b++) if (p[i][j][a][b]&&(x+a>n||y+b>x+a||ch[x+a][y+b]!='.')) return 0; return 1; } int hash(int a,int b){ return a*(a-1)/2+b; } void build(int x,int y,int i,int j){ Row++; built[Row].x=x; built[Row].y=y; built[Row].i=i; built[Row].j=j; int first=dlx.cnt+1; for (int a=0;a<4;a++) for (int b=0;b<4;b++) if (p[i][j][a][b]) dlx.link(Row,hash(x+a,y+b)); dlx.link(Row,55+i+1); dlx.L[first]=dlx.cnt; dlx.R[dlx.cnt]=first; } void addPIC(int x,int y,int i,int j){ char CHAR=i+'A'; for (int a=0;a<4;a++) for (int b=0;b<4;b++) if (p[i][j][a][b]) ch[x+a][y+b]=CHAR; } int main(){ for (int i=1;i<=n;i++) scanf("%s",ch[i]+1); dlx.init(55+12); memset(matched,0,sizeof matched); Row=0; for (int i=1;i<=n;i++) for (int j=1,imat=0;j<=i;imat=0,j++) for (int x=0;x<12&&!imat;x++) for (int y=0;y<z[x]&&!imat;y++) if (match(i,j,x,y)){ matched[x]=imat=1; build(i,j,x,y); } for (int i=1;i<=n;i++) for (int j=1;j<=i;j++) for (int x=0;x<12;x++){ if (matched[x]) continue; for (int y=0;y<z[x];y++) if (nmatch(i,j,x,y)) build(i,j,x,y); } bool found=dlx.solve(); if (!found) printf("No solution"); else { for (int i=1;i<=dlx.anscnt;i++){ int bh=dlx.ans[i]; if (!matched[built[bh].i]) addPIC(built[bh].x,built[bh].y,built[bh].i,built[bh].j); } for (int i=1;i<=n;puts(""),i++) for (int j=1;j<=i;j++) printf("%c",ch[i][j]); } return 0; }