dancing link的应用,很奇葩的遇到了传说中的PE
16*16的数独问题,dlx即可解决,惊奇的发现高二的师兄们雄踞了pascal的第一版,同样是dancing link,我的速度却只能退居第二版。
转换模型——>精确覆盖
数独问题中每个元素,每行只出现一次,每列只出现一次,每宫只出现一次,每格只出现一个元素,联想到0,1精确覆盖,建立矩阵
分为(16+16+16)*16+16*16,前三个16分别表示行,列,宫,*16表示有16种选择,后16*16表示16*16个格子。
例如第一行,第一列,已知填1号元素,则在描述这个元素的那一行,表示第一行填1号元素的位置放一,表示第一列填1号元素位置放一,表示第一宫填1号元素位置放一,表示第一行第一列放了元素的位置放一。
而对于未知的格子,则有16种可能,所以描述这个元素要分16行。
接下来就跳舞吧。
const g:array[1..16,1..16]of integer= ((1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4), (1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4), (1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4), (1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4), (5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8), (5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8), (5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8), (5,5,5,5,6,6,6,6,7,7,7,7,8,8,8,8), (9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,12), (9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,12), (9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,12), (9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,12), (13,13,13,13,14,14,14,14,15,15,15,15,16,16,16,16), (13,13,13,13,14,14,14,14,15,15,15,15,16,16,16,16), (13,13,13,13,14,14,14,14,15,15,15,15,16,16,16,16), (13,13,13,13,14,14,14,14,15,15,15,15,16,16,16,16)); var l,r,u,d,t,s,c,l1,r1:array[0..20000]of longint; f:array[1..20000]of boolean; ans,a:array[1..16,1..16]of char; s0,s1,s2,s3,s4,ss:longint; flag:boolean; procedure origin; var i:longint; begin fillchar(d,sizeof(d),0);fillchar(u,sizeof(u),0); fillchar(r,sizeof(r),0);fillchar(l,sizeof(l),0); fillchar(s,sizeof(s),0);fillchar(f,sizeof(f),false); fillchar(ans,sizeof(ans),0); s1:=16*16;s2:=s1+16*16;s3:=s2+16*16;s4:=s3+16*16;ss:=s4; r[0]:=1;l[0]:=ss; for i:=1 to ss do begin r[i]:=i+1;l[i]:=i-1;u[i]:=i;d[i]:=i end; r[ss]:=0; for i:=ss+1 to ss+s0 do begin l[i]:=i;r[i]:=i end; ss:=ss+s0 end; procedure link(x,y:longint); begin inc(ss);c[ss]:=y;t[ss]:=x; l[ss]:=l[x];r[l[x]]:=ss;l[x]:=ss;r[ss]:=x; u[ss]:=u[y];d[u[y]]:=ss;u[y]:=ss;d[ss]:=y; inc(s[y]) end; procedure ins(x,y:longint); var i,xx:longint; begin for i:=1 to 16 do begin xx:=(x-1)*16; link(s0+i+s4,xx+i); xx:=s1+(y-1)*16; link(s0+i+s4,xx+i); xx:=s2+(g[x,y]-1)*16; link(s0+i+s4,xx+i); xx:=s3+(x-1)*16+y; link(s0+i+s4,xx) end; s0:=s0+16; end; procedure ins2(x,y,z:longint); var xx:longint; begin xx:=(x-1)*16; link(s0+1+s4,xx+z); xx:=s1+(y-1)*16; link(s0+1+s4,xx+z); xx:=s2+(g[x,y]-1)*16; link(s0+1+s4,xx+z); xx:=s3+(x-1)*16+y; link(s0+1+s4,xx); inc(s0) end; procedure del(x:longint); var i,j:longint; begin r[l[x]]:=r[x];l[r[x]]:=l[x]; i:=x; while d[i]<>x do begin i:=d[i];j:=i; while r[j]<>i do begin j:=r[j]; if j<>t[i] then begin u[d[j]]:=u[j];d[u[j]]:=d[j]; dec(s[c[j]]) end end end end; procedure rel(x:longint); var i,j:longint; begin r[l[x]]:=x;l[r[x]]:=x; i:=x; while u[i]<>x do begin i:=u[i];j:=i; while l[j]<>i do begin j:=l[j]; if j<>t[i] then begin u[d[j]]:=j;d[u[j]]:=j; inc(s[c[j]]) end end end end; procedure dfs(k:longint); var x,min,y,i,j:longint; begin if r[0]=0 then begin flag:=true;exit end; x:=0;min:=maxlongint;y:=0; while r[x]<>0 do begin x:=r[x]; if s[x]<min then begin min:=s[x];y:=x end end; x:=y;del(x);i:=x; while d[i]<>x do begin i:=d[i];j:=i;f[t[i]]:=true; while r[j]<>i do begin j:=r[j]; if j<>t[i] then del(c[j]) end; dfs(k+1); if flag then exit; j:=i; while l[j]<>i do begin j:=l[j]; if j<>t[i] then rel(c[j]) end; f[t[i]]:=false end; rel(x) end; procedure getout; var x,x1,y1,k1,i,j:longint; begin fillchar(ans,sizeof(ans),0); for i:=s4+1 to s4+s0 do if f[i] then begin if i=1056 then y1:=y1; x:=r[i]; if c[x] mod 16<>0 then x1:=c[x] div 16 + 1 else x1:=c[x] div 16; k1:=c[x] mod 16; if k1=0 then k1:=16; x:=r[x]; if (c[x]-s1) mod 16<>0 then y1:=(c[x]-s1) div 16 + 1 else y1:=(c[x]-s1) div 16; ans[x1,y1]:=chr(k1+64) end; for i:=1 to 16 do begin for j:=1 to 16 do write(ans[i,j]); writeln end; readln;writeln end; procedure init; var i,j:longint; begin s0:=0; for i:=1 to 16 do begin for j:=1 to 16 do begin read(a[i,j]); if a[i,j]='-' then s0:=s0+16 else inc(s0) end; readln end; origin; s0:=0; for i:=1 to 16 do for j:=1 to 16 do begin if a[i,j]='-' then ins(i,j) else ins2(i,j,ord(a[i,j])-64) end; r1:=r;l1:=l; flag:=false; dfs(0); r:=r1;l:=l1; if flag then getout end; begin while not seekeof do init; end.
对于PE,每组数据之间要空行
poj 2676
const map:array[1..9,1..9]of longint=( (1,1,1,2,2,2,3,3,3), (1,1,1,2,2,2,3,3,3), (1,1,1,2,2,2,3,3,3), (4,4,4,5,5,5,6,6,6), (4,4,4,5,5,5,6,6,6), (4,4,4,5,5,5,6,6,6), (7,7,7,8,8,8,9,9,9), (7,7,7,8,8,8,9,9,9), (7,7,7,8,8,8,9,9,9) ); n=9; max=1400; var a,t,c,l,r,u,d,s:array[0..100000]of longint; f:array[0..100000]of boolean; ans:array[1..9,1..9]of longint; s1,ss,tt:longint; flag:boolean; procedure del(x:longint); var i,j:longint; begin r[l[x]]:=r[x];l[r[x]]:=l[x]; i:=x; while d[i]<>x do begin i:=d[i];j:=i; while r[j]<>i do begin j:=r[j]; if j<>t[i] then begin d[u[j]]:=d[j];u[d[j]]:=u[j]; dec(s[c[j]]) end end end end; procedure rel(x:longint); var i,j:longint; begin r[l[x]]:=x;l[r[x]]:=x; i:=x; while d[i]<>x do begin i:=d[i];j:=i; while r[j]<>i do begin j:=r[j]; if j<>t[i] then begin d[u[j]]:=j;u[d[j]]:=j; inc(s[c[j]]) end end end end; procedure dfs; var x,y,min,i,j:longint; begin if r[0]=0 then begin flag:=true;exit end; x:=0;min:=maxlongint;y:=0; while r[x]<>0 do begin x:=r[x]; if s[x]<min then begin min:=s[x];y:=x end end; if min>1073741819 then begin flag:=true;exit end; x:=y;del(x);i:=x; while d[i]<>x do begin i:=d[i];j:=i;f[t[i]]:=true; while r[j]<>i do begin j:=r[j]; if j<>t[i] then del(c[j]) end; dfs; if flag then exit; j:=i; while r[j]<>i do begin j:=r[j]; if j<>t[i] then rel(c[j]) end; f[t[i]]:=false end end; procedure link(x:longint); begin inc(ss);t[ss]:=s1;c[ss]:=x; r[l[s1]]:=ss;l[ss]:=l[s1];l[s1]:=ss;r[ss]:=s1; d[u[x]]:=ss;u[ss]:=u[x];u[x]:=ss;d[ss]:=x; inc(s[x]) end; procedure origin; var i:longint; begin fillchar(d,sizeof(d),0);fillchar(u,sizeof(u),0); fillchar(l,sizeof(l),0);fillchar(r,sizeof(r),0); fillchar(t,sizeof(t),0);fillchar(c,sizeof(c),0); fillchar(s,sizeof(s),0);fillchar(f,sizeof(f),false); for i:=1 to max>>1 do begin l[i]:=i-1;r[i]:=i+1 end; r[max>>1]:=0; r[0]:=1;l[0]:=max>>1; for i:=0 to max>>1 do begin u[i]:=i;d[i]:=i; end; for i:=max>>1+1 to max do begin r[i]:=i;l[i]:=i end; s1:=max>>1;ss:=max end; procedure getout; var i,j,x,x1,x2:longint; begin for i:=max>>1+1 to s1 do if f[i] then begin if i=1034 then x:=x; x:=c[l[i]]; x:=x-9*9-9*9-9*9; x1:=(x div 9)+1; x2:=x mod 9; if x2=0 then begin x2:=9;dec(x1) end; ans[x1,x2]:=a[i] end; for i:=1 to n do begin for j:=1 to n do write(ans[i,j]); writeln end end; procedure init; var i,m,j,x,k:longint; y:char; begin origin; for i:=1 to n do begin for j:=1 to n do begin read(y);x:=ord(y)-48; if x=0 then begin for k:=1 to 9 do begin inc(s1);a[s1]:=k; m:=(i-1)*n;link(m+k); m:=n*n; link(m+(j-1)*n+k); m:=m+m; link(m+(map[i,j]-1)*n+k); m:=m+n*n; link(m+(i-1)*n+j) end end else begin inc(s1);k:=x;a[s1]:=k; m:=(i-1)*n;link(m+k); m:=n*n; link(m+(j-1)*n+k); m:=m+m; link(m+(map[i,j]-1)*n+k); m:=m+n*n; link(m+(i-1)*n+j) end end; readln end; flag:=false; for i:=1 to max>>1 do if s[i]=0 then s[i]:=maxlongint; dfs; if flag then getout end; begin readln(tt); for tt:=1 to tt do init end.
poj3076 c++版
#include <cstdio> #include <algorithm> #include <cstring> #include <iostream> #include <string> #include <vector> #include <cassert> #include <set> const int oo=1073741819; using namespace std; struct pp{ int l,r,w; }P[200000]; set < int > g[5000]; int l[200000],r[200000],u[200000],d[200000],R[200000],C[200000]; int row[200000],clo[200000],id[20][20],S[200000]; bool v[200000]; int n,m,ss; char ch[20][20],ans[20][20]; int ori() { ++ss; l[ss]=r[ss]=u[ss]=d[ss]=ss,R[ss]=C[ss]=0; S[ss]=0; return ss; } void linkud(int x,int y) { d[x]=y,u[y]=x; } void linklr(int x,int y) { r[x]=y,l[y]=x; } void add(int x,int y) { ori(); R[ss]=row[x],C[ss]=clo[y]; int last=u[clo[y]]; linkud(last,ss),linkud(ss,clo[y]); last=l[row[x]]; linklr(last,ss),linklr(ss,row[x]); S[C[ss]]++; } void build() { ss=0; for (int i=1;i<=n;i++) v[i]=0; for (int i=1;i<=n;i++) row[i]=ori(); for (int i=0;i<=m;i++) clo[i]=ori(); for (int i=1;i<n;i++) linkud(row[i],row[i+1]); linkud(row[n],row[1]); for (int i=0;i<m;i++) linklr(clo[i],clo[i+1]); linklr(clo[m],clo[0]); for (int i=1;i<=n;i++) { set < int > :: iterator it=g[i].begin(); for (;it!=g[i].end();it++) add(i,*it); } // cout<<ss<<endl; } void del(int x) { linklr(l[x],r[x]); for (int i=x;d[i]!=x;) { i=d[i]; for (int y=i;r[y]!=i;) { y=r[y]; if (R[y] && C[y]) { linkud(u[y],d[y]); S[C[y]]--; } } } } void rel(int x) { linklr(l[x],x),linklr(x,r[x]); for (int i=x;u[i]!=x;) { i=u[i]; for (int y=i;l[y]!=i;) { y=l[y]; if (R[y] && C[y]) { linkud(u[y],y),linkud(y,d[y]); S[C[y]]++; } } } } bool DLX(int s,int step) { if (r[s]==s) return 1; int x,Min=oo,Mini=0; for (int i=s;r[i]!=s;) { i=r[i]; if (S[i]<Min) Min=S[i],Mini=i; } x=Mini,del(x); for (int i=x;d[i]!=x;) { i=d[i]; for (int y=i;r[y]!=i;) { y=r[y]; if (R[y] && C[y]) del(C[y]); } v[R[i]]=1; if (DLX(s,step+1)) return 1; v[R[i]]=0; for (int y=i;l[y]!=i;) { y=l[y]; if (R[y] && C[y]) rel(C[y]); } } rel(x); return 0; } int main() { int tot=0; for (int lx=1;lx<=13;lx+=4) for (int ly=1;ly<=13;ly+=4) { ++tot; for (int i=lx;i<=lx+3;i++) for (int j=ly;j<=ly+3;j++) id[i][j]=tot; } for (;scanf("%s",ch[1]+1)==1;) { for (int i=2;i<=16;i++) scanf("%s",ch[i]+1); n=0,m=16*16+16*16*3; for (int i=1;i<=16;i++) for (int j=1;j<=16;j++) if (ch[i][j]=='-') { for (int k=1;k<=16;k++) { ++n,g[n].clear(); int p=(i-1)*16+j; g[n].insert(p); p=16*16+(i-1)*16+k; g[n].insert(p); p=16*16+16*16+(j-1)*16+k; g[n].insert(p); p=16*16+16*16*2+(id[i][j]-1)*16+k; g[n].insert(p); P[n].l=i,P[n].r=j,P[n].w=k+'A'-1; } } else { int k=ch[i][j]-'A'+1; ++n,g[n].clear(); int p=(i-1)*16+j; g[n].insert(p); p=16*16+(i-1)*16+k; g[n].insert(p); p=16*16+16*16+(j-1)*16+k; g[n].insert(p); p=16*16+16*16*2+(id[i][j]-1)*16+k; g[n].insert(p); P[n].l=i,P[n].r=j,P[n].w=k+'A'-1; } build(); // cout<<ss<<' '<<S[clo[1]]<<endl; DLX(clo[0],0); for (int i=1;i<=n;i++) if (v[row[i]]) { ans[P[i].l][P[i].r]=P[i].w; } for (int i=1;i<=16;i++) { for (int j=1;j<=16;j++) printf("%c",ans[i][j]); printf("\n"); } printf("\n"); } return 0; }