用DLX来解决16*16 数独问题。
#include <iostream> #include<stdio.h> #include<cmath> #include<string.h> #include<algorithm> #include<string> #include<vector> using namespace std; const int maxn = 2010; const int maxnode = 20010; const int maxr = 5010; struct DLX { int n,sz; // 列数,节点总数 int S[maxn]; //各列节点数 int row[maxnode],col[maxnode]; //各节点行列标号 int L[maxnode],R[maxnode],U[maxnode],D[maxnode]; // 十字链表 记录节点ID int ansd,ans[maxr]; //解 void init(int n) { this->n=n; //虚拟节点 for(int i=0;i<=n;i++) { U[i]=i,D[i]=i,L[i]=i-1,R[i]=i+1; } R[n]=0,L[0]=n; sz=n+1; memset(S,0,sizeof S); } void addrow(int r,vector<int>columns) //添加一行 { int first=sz; for(int i=0;i<(int)columns.size();i++) { int c=columns[i]; L[sz]=sz-1;R[sz]=sz+1;D[sz]=c,U[sz]=U[c]; D[U[c]]=sz;U[c]=sz; row[sz]=r;col[sz]=c; S[c]++;sz++; } R[sz-1]=first,L[first]=sz-1; } #define FOR(i,A,s) for(int i=A[s];i!=s;i=A[i]) void remove(int c) { L[R[c]]=L[c]; R[L[c]]=R[c]; FOR(i,D,c) FOR(j,R,i) { U[D[j]]=U[j]; D[U[j]]=D[j]; --S[col[j]]; } } void restore(int c) { FOR(i,U,c) FOR(j,L,i) { ++S[col[j]]; U[D[j]]=j; D[U[j]]=j; } L[R[c]]=c; R[L[c]]=c; } bool dfs(int d) { if(R[0]==0) { ansd=d; //找到了解 return 1; } //找到S最小的列c int c=R[0]; //第一个为删除的列 FOR(i,R,0) if(S[i]<S[c]) c=i; remove(c); FOR(i,D,c) { ans[d]=row[i]; FOR(j,R,i) remove(col[j]); if(dfs(d+1)) return 1; FOR(j,L,i) restore(col[j]); } restore(c); return 0; } bool solve(vector<int> &v) { v.clear(); if(!dfs(0)) return 0; for(int i=0;i<ansd;i++) v.push_back(ans[i]); return 1; } }; DLX sudoku; struct Sel { int r,c,v; }S[maxr]; char G[20][20]; int get_id(int x,int y) { return 4*(x/4)+y/4; } void add(int id,int r,int c,int v) { vector<int>x; x.push_back(16*r+c+1); x.push_back(16*16+16*r+v+1); x.push_back(16*16*2+16*c+v+1); x.push_back(16*16*3+16*get_id(r,c)+v+1); sudoku.addrow(id,x); } int main() { int ca=0; while(~scanf("%s",G[0])) { if(ca) puts(""); ca++; for(int i=1;i<16;i++) scanf("%s",G[i]); sudoku.init(1024); int cnt=1; for(int i=0;i<16;i++) { for(int j=0;j<16;j++) { if(G[i][j]=='-') { for(int k=0;k<16;k++) { S[cnt].r=i; S[cnt].c=j; S[cnt].v=k; add(cnt,i,j,k); cnt++; } } else { S[cnt].r=i; S[cnt].c=j; S[cnt].v=G[i][j]-'A'; add(cnt,i,j,G[i][j]-'A'); cnt++; } } } vector<int>ans; ans.clear(); sudoku.solve(ans); for(int i=0;i<ans.size();i++) { int tmp=ans[i]; G[S[tmp].r][S[tmp].c]=S[tmp].v+'A'; } for(int i=0;i<16;i++) printf("%s\n",G[i]); } return 0; }