【POJ3074】Sudoku DLX(Dancing Links)
數獨就要DLX,不然不樂意。
數獨的DLX構造:9*9個點每一個點有9種選擇,這構成了DLX的729行,每行、列、陣有限制,均為9行(/列/陣),然後每行(/列/陣)都有九種數的情況。於是就有了3*9*9列。可是由於一個位置僅僅能選一個,所以又有9*9列,每列連接一個點的九種選數情況。
終於有4*9*9=324列,9*9*9=729行。
處理:
有些點已經有數了,可是這並不重要,我們僅僅須要給這個點加上一個行,為它已經選的數。而不要把9種情況都加上,這樣在有精確覆蓋的情況下(即有解),第四部分的某列在縱向就僅僅連接一個節點,顯然這個節點是必選的,所以不會出錯(當然你要是依舊給這個有值節點在DLX中加9行的話。那我也沒招,不要問我為什麽錯,好吧你不會這麽傻吧?)。
而其他沒有初始值的數獨點,自然就加舊行了沒疑問吧?
說一個跟空間復雜度相關的事。就是一行有且僅有4個節點。分別在行、列、陣、位置這四部分的列中,那麽總節點數(不算輔助節點)就應該最多是729*4。而實際上標準數獨都是有唯一解的,所以須要的節點將遠遠小於這個數。
再說說時間復雜度:由於我們能夠為DLX加一個優化。就是每次選一個列中節點最少的列繼續DLX的過程,所以我們盡管保留了已經有值的節點,可是實際上最開始就選擇了它們,而若數獨有解。這也是必然選擇的。所以並不會出現由於層數過多而導致回溯過度而TLE的情況,也就是說它還是非常快的。當然。強迫癥神馬的我也管不了。你要是樂意把已賦值點刪掉我也不攔著,但不像上一篇代碼了。你要這麽寫的話,我並不會給你提供代碼支持。
事實上這麽寫最重要的原因就是:代。碼!好!
寫!
好吧,我把我好寫好讀的代碼貼上來吧!提示:要讀代碼先看define!事實上這道題的define非常easy。並沒有一些惡心人的for循環define,你要是認為讀著惡心一定是你的問題了。
貼代碼:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 800 #define M 400 #define NN 5000 #define inf 0x3f3f3f3f #define Li_Sdk 3 #define Gi_Sdk 9 #define Su_Sdk 81 using namespace std; char TS[N]; struct DLX { int elist,eline; int id[Gi_Sdk+1][Gi_Sdk+1][Gi_Sdk+1]; int eid[4][Gi_Sdk][Gi_Sdk]; bool map[M][N]; int U[NN],D[NN],L[NN],R[NN],C[NN],V[NN]; int H[N],T[M],cnt; int ans[NN]; bool visit[M],vist[M]; inline void init() { int i,j,k,_i,_j; for(i=1;i<=Gi_Sdk;i++) for(j=1;j<=Gi_Sdk;j++) for(k=1;k<=Gi_Sdk;k++) id[i][j][k]=++eline; for(i=1;i<=Gi_Sdk;i++)/*行*/ { for(j=1;j<=Gi_Sdk;j++)/*數*/ { int A=eid[0][i][j]=++elist; for(k=1;k<=Gi_Sdk;k++)/*列*/ { int B=id[i][k][j]; map[A][B]=1; } } } for(i=1;i<=Gi_Sdk;i++)/*列*/ { for(j=1;j<=Gi_Sdk;j++)/*數*/ { int A=eid[1][i][j]=++elist; for(k=1;k<=Gi_Sdk;k++)/*行*/ { int B=id[k][i][j]; map[A][B]=1; } } } for(i=0;i<Li_Sdk;i++)for(j=0;j<Li_Sdk;j++)/*九宮格*/ { for(k=1;k<=Gi_Sdk;k++)/*數*/ { int A=eid[2][i*Li_Sdk+j+1][k]=++elist; for(_i=1;_i<=Li_Sdk;_i++)for(_j=1;_j<=Li_Sdk;_j++)/*格內點*/ { int B=id[i*Li_Sdk+_i][j*Li_Sdk+_j][k]; map[A][B]=1; } } } for(i=1;i<=Gi_Sdk;i++)for(j=1;j<=Gi_Sdk;j++)/*點的位置*/ { int A=eid[3][i][j]=++elist; for(k=1;k<=Gi_Sdk;k++)/*點的9個數*/ { int B=id[i][j][k]; map[A][B]=1; } } /* for(j=1;j<=eline;j++) { for(i=1;i<=elist;i++) { printf("%d",map[i][j]); } puts(""); } */ /*本題的數獨是正常數獨,所以有下面固定信息。*/ /*合計eline即DLX的行有9*9*9=729行,即每一個位置的九種數字選擇。*/ /*合計elist即DLX的列有4*9*9=324列。即行、列、九宮格、位置的4種精確覆蓋*/ } inline void clear() { cnt=0; memset(U,0,sizeof(U)); memset(D,0,sizeof(D)); memset(L,0,sizeof(L)); memset(R,0,sizeof(R)); memset(C,0,sizeof(C)); memset(H,0,sizeof(H)); memset(T,0,sizeof(T)); memset(ans,0,sizeof(ans)); memset(vist,0,sizeof(vist)); memset(visit,0,sizeof(visit)); } inline void newnode(int x,int y) { C[++cnt]=y;V[cnt]=x;T[y]++; if(!H[x])H[x]=L[cnt]=R[cnt]=cnt; else L[cnt]=H[x],R[cnt]=R[H[x]]; R[H[x]]=L[R[H[x]]]=cnt,H[x]=cnt; U[cnt]=U[y],D[cnt]=y; U[y]=D[U[y]]=cnt; } inline void remove(int x) { for(int i=D[x];i!=x;i=D[i]) { for(int j=R[i];j!=i;j=R[j]) { U[D[j]]=U[j]; D[U[j]]=D[j]; T[C[j]]--; } } L[R[x]]=L[x]; R[L[x]]=R[x]; } inline void resume(int x) { for(int i=U[x];i!=x;i=U[i]) { for(int j=L[i];j!=i;j=L[j]) { U[D[j]]=j; D[U[j]]=j; T[C[j]]++; } } L[R[x]]=x; R[L[x]]=x; } inline void build() { clear(); int i,j,k; cnt=4*Su_Sdk; for(i=1;i<=cnt;i++) { U[i]=D[i]=i; L[i]=L[0],R[i]=0; L[0]=R[L[0]]=i; } for(i=0;i<Gi_Sdk;i++)for(j=0;j<Gi_Sdk;j++) { int get=i*Gi_Sdk+j; int alp=TS[get]-‘.‘; if(!alp) { for(k=get*Gi_Sdk+1;k<=get*Gi_Sdk+Gi_Sdk;k++) for(int temp=1;temp<=elist;temp++) if(map[temp][k])newnode(k,temp); } else { k=get*Gi_Sdk+TS[get]-‘0‘; for(int temp=1;temp<=elist;temp++) if(map[temp][k])newnode(k,temp); } } } inline bool dfs() { if(!R[0])return true; int S=R[0],W=T[S],i,j; for(i=R[S];i;i=R[i])if(T[i]<W) { W=T[i]; S=i; } remove(S); for(i=D[S];i!=S;i=D[i]) { ans[(V[i]-1)/9]=(V[i]-1)%9+1; for(j=R[i];j!=i;j=R[j])remove(C[j]); if(dfs())return true; for(j=L[i];j!=i;j=L[j])resume(C[j]); } resume(S); return false; } inline void ret(){for(int i=0;i<Su_Sdk;i++)printf("%d",ans[i]);} }dlx; int main() { // freopen("test.in","r",stdin); // freopen("my.out","w",stdout); int n,m; dlx.init(); while(scanf("%s",TS),TS[0]!=‘e‘) { dlx.build(); dlx.dfs(); dlx.ret(); puts(""); } // fclose(stdin); // fclose(stdout); return 0; }
【POJ3074】Sudoku DLX(Dancing Links)