B32 Dancing Links 舞蹈链 数独
视频链接:133 Dancing Links 舞蹈链 数独_哔哩哔哩_bilibili
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=3245; //点729*4+列头324 int n,m,cnt; //矩阵的长,宽,点的编号 int u[N],d[N],l[N],r[N]; //每个点的上下左右 int row[N],col[N]; //每个点所在行,列 int h,t; //每行的头,尾指针 int s[N]; //每列的节点数 int ans[N]; //选了那些行 int a[10][10];//数独的数 void init(){ //初始化第0行的列表头 for(int y=0; y<=m; y++){ u[y]=d[y]=y; l[y]=y-1; r[y]=y+1; } l[0]=m; r[m]=0; cnt=m+1; //下一个点的编号 } void link(int x,int y){ //在x行y列插入点 row[cnt]=x; col[cnt]=y; s[y]++; u[cnt]=u[y]; //y...u[y]←→cnt←→y d[u[y]]=cnt; d[cnt]=y; u[y]=cnt; l[cnt]=t; //h...t←→cnt←→h r[t]=cnt; r[cnt]=h; l[h]=cnt; t=cnt++; //t指向cnt, 然后cnt+1 } void remove(int y){ //删除y列与关联行 r[l[y]]=r[y], l[r[y]]=l[y]; for(int i=d[y]; i!=y; 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 y){ //恢复y列与关联行 r[l[y]]=y, l[r[y]]=y; for(int i=u[y]; i!=y; i=u[i]) //向上 for(int j=l[i]; j!=i; j=l[j]) //向左 u[d[j]]=j, d[u[j]]=j, s[col[j]]++; } bool dance(int dep){ if(r[0]==0){ for(int i=0,x,y,v;i<dep;i++){ x=(ans[i]-1)/9/9; //链表行→数独 y=(ans[i]-1)/9%9; v=(ans[i])%9; a[x][y]=v?v:9; } for(int i=0;i<=8;i++){ for(int j=0;j<=8;j++)printf("%d ",a[i][j]); puts(""); } return true; } int y=r[0]; //找到点最少的列 for(int i=r[0];i;i=r[i]) if(s[i]<s[y])y=i; remove(y); for(int i=d[y];i!=y;i=d[i]){ ans[dep]=row[i]; for(int j=r[i];j!=i;j=r[j]) remove(col[j]); if(dance(dep+1)) return true; for(int j=l[i];j!=i;j=l[j]) resume(col[j]); } resume(y); return false; } int main(){ n=729; m=324; init(); for(int i=0; i<9; i++){ //数独的行 for(int j=0,x; j<9; j++){ //数独的列 scanf("%d",&x);a[i][j]=x; for(int k=1; k<=9; k++){ //9个数 if(x==0||x==k){ h=t=cnt; //每行的第一个点 int r=i*9*9+j*9+k; //数独→链表行 link(r,i*9+j+1); link(r,81*1+i*9+k); link(r,81*2+j*9+k); link(r,81*3+(i/3*3+j/3)*9+k); } } } } dance(0); }