Dancing Links是使用双向循环十字链表的数据结构通过dfs来实现解决精确覆盖问题的强有力的武器。
而数独问题可以转化为精确覆盖问题。
通过将每个限制转化为列。每个决策转化为行。
建模型:
行数为9*9*9,数独中,第i行j列放数字k的状态存储在图中第(i*9+j)*9+k行中
列数为9*9+9*9+9*9+9*9,
其中第一个9*9代表第i格是否已填满,
用第二个9*9确保每行的数字唯一且均出现一次
第三个9*9确保每列的数字唯一且出现一次
第四个9*9确保每宫的数字唯一出现1次
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi 3.1415926535 # define eps 1e-4 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; inline int Scan() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=9; //Code begin... const int MaxN=N*N*N+10, MaxM=N*N*4+10, maxnode=MaxN*4+MaxM+10; char g[MaxN]; struct DLX{ int n, m, size; int U[maxnode], D[maxnode], R[maxnode], L[maxnode], Row[maxnode], Col[maxnode]; int H[MaxN], S[MaxM], ansd, ans[MaxN]; void init(int _n, int _m){ n=_n; m=_m; FOR(i,0,m) 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(i,1,n) 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 (R[0]==0) { FO(i,0,d) g[(ans[i]-1)/9]=(ans[i]-1)%9+'1'; FO(i,0,N*N) printf("%c",g[i]); printf(" "); return true; } 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]) { ans[d]=Row[i]; for (int j=R[i]; j!=i; j=R[j]) remove(Col[j]); if (Dance(d+1)) return true; for (int j=L[i]; j!=i; j=L[j]) resume(Col[j]); } resume(c); return false; } }dlx; 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/3)*3+(j/3))*N+k; } int main () { while (~scanf("%s",g)&&strcmp(g,"end")) { dlx.init(N*N*N,N*N*4); int r, c1, c2, c3, c4; FO(i,0,N) FO(j,0,N) FOR(k,1,N) if (g[i*N+j]=='.'||g[i*N+j]=='0'+k) { place(r,c1,c2,c3,c4,i,j,k); dlx.Link(r,c1); dlx.Link(r,c2); dlx.Link(r,c3); dlx.Link(r,c4); } dlx.Dance(0); } return 0; }