3074

来源:互联网 发布:数据库内找账号密码 编辑:程序博客网 时间:2024/06/07 07:14
算法dlx。下面只讲如何建模。
就是一个729*324的矩阵。
行数:数独共有81格,每个有9种数可填,∴81*9=729
列数:数独每格只能填一次(81格),每行、每列、每个九宫格内有且仅有九种数(3*9*9),∴81+3*9*9=324
然后将读进来的数所对应的行都删去,跑一遍精确覆盖,然后重新加入这些行。
反正思路是这样的。下面的代码还没调出来,千万不要看!
#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>using namespace std;#define rep(i,j,k) for(i=j;i<=k;++i)#define per(i,j,k) for(i=j;i>=k;--i)#define ll long long#define db double#define mkp(x,y) make_pair(x,y)#define pii pair<int,int>#define X first#define Y secondconst int N=729,M=324,NM=250000;struct DLX{int L[NM],R[NM],U[NM],D[NM],ro[NM],co[NM],H[N+1],S[M+1],cnt,sz,ans[82];//H为行首,S为每列元素个数 void reset(){int i;rep(i,0,M)S[i]=0,L[i]=i-1,R[i]=i+1,U[i]=D[i]=i;L[0]=M,R[M]=0,sz=M+1;memset(H,-1,sizeof H);}void ins(int x,int y){++S[co[sz]=y],ro[sz]=x;//确定所在行、列 U[D[sz]=D[y]]=sz;U[D[y]=sz]=y;//将sz插入y和D[y]中if(H[x]<0)H[x]=L[sz]=R[sz]=sz;else{L[R[sz]=R[H[x]]]=sz;R[L[sz]=H[x]]=sz;}//将sz插入H[x]和R[H[x]]中++sz; }void init(){int i,j,k,x;rep(i,1,9)rep(j,1,9)rep(k,1,9){x=(i-1)*81+(j-1)*9+k;ins(x,(i-1)*9+j),ins(x,81+(i-1)*9+k),ins(x,162+(j-1)*9+k),ins(x,243+((i-1)/3*3+(j-1)/3)*9+k);}}void del(int c){R[L[R[c]]=L[c]]=R[c];int i,j;for(i=D[c];i!=c;i=D[i])for(j=R[i];j!=i;j=R[j])D[U[D[j]]=U[j]]=D[j],--S[co[j]];}void add(int c){R[L[c]]=L[R[c]]=c;int i,j;for(i=U[c];i!=c;i=U[i])for(j=L[i];j!=i;j=L[j])++S[co[U[D[j]]=D[U[j]]=j]];}bool DFS(){if(!R[0])return 1;int c,i,j;for(i=c=R[0];i;i=R[i])if(S[c]>S[i])c=i;//找出元素最多的一列 del(c);for(i=D[c];i!=c;i=D[i]){for(j=R[i];j!=i;j=R[j])del(co[j]);ans[(ro[i]-1)/9]=(ro[i]-1)%9+1;if(DFS())return 1;for(j=L[i];j!=i;j=L[j])add(co[j]);}add(c);return 0;}void solve(string s){int tmp[81],i,x,y;memset(ans,0,sizeof ans);rep(i,0,80)if(s[i]!='.'){ans[i+1]=s[i]-'0';del(co[x=H[tmp[i]=9*(i+1)+ans[i+1]]]);for(y=R[x];y!=x;y=R[y])del(co[y]);}DFS();rep(i,0,80)if(s[i]!='.'){add(co[x=H[tmp[i]]]);for(y=R[x];y!=x;y=R[y])add(co[y]);}rep(i,1,81)printf("%d",ans[i]);}}dlx;int main(){string s;dlx.reset();dlx.init();while(1){cin>>s;if(s=="end")break;dlx.solve(s);}return 0;}


原创粉丝点击