I'm going to dance 数独问题 poj 3076

9 篇文章 0 订阅
7 篇文章 0 订阅

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值