题目:
POJ3047
思路:
1.情况数:9 * 9 * 9 (81格,每格有9个状态)
2.条件数:每个格子是否已填写,每行,每列,每宫的数不重复(数独的规则),共9 * 9 * 4种
3.情况数对应行数,条件数对应列数,这样就能转化为精准覆盖的问题了,选择81行保证每一列有且仅有一个1.
4.行分配:每个格子有9种情况,则给每个格子分配9行,在该9行内,第x行填1,表示这个格子填了x(1~9)。那么坐标(i,j)填k,对应第(i * 9+j)* 9+k行填1,push((i * 9+j)* 9+k,满足的条件)
5.列分配:满足4个条件具体分为:
[0, 81)列 分别对应了81个格子是否被放置了数字。
[82, 2 * 81)列 分别对应了9行,每行[1, 9]个数字的放置情况;
[2 * 81, 3 * 81)列 分别对应了9列,每列[1, 9]个数字的放置情况;
[3 * 81, 4 * 81)列 分别对应了9个“宫”,每“宫”[1, 9]个数字的放置
6.4和5两点结合就可以得到:
在(i,j)位置放了k,满足条件:
(1)第i * 9+j+1格放了,push((i * 9+j) * 9+k,i * 9+j+1);
(2)第i行的k放了,push((i * 9+j) * 9+k,9 * 9+i * 9+k);
(3)第j列的k放了,push((i * 9+j) * 9+k,9 * 9 * 2+j * 9+k);
(4)第((i/3) *3+(j/3))宫的k放了,push((i * 9+j) * 9+k,9 * 9 * 3+((i/3) * 3+(j/3)) * 9+k);
每一行最多只有4个1,因为只填了一个数(只代表一个格子的状态),也有可能全为0(因为(i,j)填了k,其他的情况就都排除了,不能填)那么就不push到图中。
所以要选出81行精准覆盖所有列的1,跑一次DLX即可
#include <iostream>
#include <cstring>
using namespace std;
static const int MAXN=9*9*9+10;
static const int MAXM=9*9*4+10;
static const int MAXNODE=MAXN*4+MAXM+10;
char g[MAXN];
struct DLX{
int n,m,siz;
int U[MAXNODE],D[MAXNODE],L[MAXNODE],R[MAXNODE],Row[MAXNODE],Col[MAXNODE];
int H[MAXN],S[MAXM];
int ansd,ans[MAXN];
void init(int _n,int _m)
{
n=_n;
m=_m;
for(int i=0;i<=m;i++)
{
S[i]=0;
U[i]=D[i]=i;
L[i]=i-1;
R[i]=i+1;
}
R[m]=0;L[0]=m;
siz=m;
for(int i=1;i<=n;i++)
H[i]=-1;
}
void push(int r,int c)
{
++S[Col[++siz]=c];
Row[siz]=r;
D[siz]=D[c];
U[D[c]]=siz;
U[siz]=c;
D[c]=siz;
if(H[r]<0)
H[r]=L[siz]=R[siz]=siz;
else
{
R[siz]=R[H[r]];
L[R[H[r]]]=siz;
L[siz]=H[r];
R[H[r]]=siz;
}
}
void del(int c)
{
L[R[c]]=L[c];
R[L[c]]=R[c];
for(int i=D[c];i!=c;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 recover(int c)
{
for(int i=U[c];i!=c;i=U[i])
for(int j=L[i];j!=i;j=L[j])
++S[Col[U[D[j]]=D[U[j]]=j]];
L[R[c]]=R[L[c]]=c;
}
bool dancing(int d)
{
if(R[0]==0)
{
for(int i=0;i<d;i++)
g[(ans[i]-1)/9]=(ans[i]-1)%9+'1';
for(int i=0;i<9*9;i++)
cout<<g[i];
cout<<endl;
return true;
}
int c=R[0];
for(int i=R[0];i!=0;i=R[i])
if(S[i]<S[c])
c=i;
del(c);
for(int i=D[c];i!=c;i=D[i])
{
ans[d]=Row[i];
for(int j=R[i];j!=i;j=R[j])
del(Col[j]);
if(dancing(d+1))
return true;
for(int j=L[i];j!=i;j=L[j])
recover(Col[j]);
}
recover(c);
return false;
}
};
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0),cout.tie(0);
while(cin>>g)
{
if(g[0]=='e')
break;
DLX dlx;
dlx.init(9*9*9,9*9*4);
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
for(int k=1;k<=9;k++)
if(g[i*9+j]=='.' || g[i*9+j]=='0'+k)///若为.可以放置1~9,否则只能放置k
{
dlx.push((i*9+j)*9+k,i*9+j+1);
dlx.push((i*9+j)*9+k,9*9+i*9+k);
dlx.push((i*9+j)*9+k,9*9*2+j*9+k);
dlx.push((i*9+j)*9+k,9*9*3+((i/3)*3+(j/3))*9+k);
}
dlx.dancing(0);
}
return 0;
}
题目:
ZOJ3122
思路:
同上,只是规模变大了
#include <iostream>
#include <cstring>
using namespace std;
static const int MAXN=16*16*16+10;
static const int MAXM=16*16*4+10;
static const int MAXNODE=MAXN*4+MAXM+10;
char str[MAXN];
struct DLX{
int n,m,siz;
int U[MAXNODE],D[MAXNODE],L[MAXNODE],R[MAXNODE],Row[MAXNODE],Col[MAXNODE];
int H[MAXN],S[MAXM];
int ansd,ans[MAXN];
void init(int _n,int _m)
{
n=_n;
m=_m;
for(int i=0;i<=m;i++)
{
S[i]=0;
U[i]=D[i]=i;
L[i]=i-1;
R[i]=i+1;
}
R[m]=0;L[0]=m;
siz=m;
for(int i=1;i<=n;i++)
H[i]=-1;
}
void push(int r,int c)
{
++S[Col[++siz]=c];
Row[siz]=r;
D[siz]=D[c];
U[D[c]]=siz;
U[siz]=c;
D[c]=siz;
if(H[r]<0)
H[r]=L[siz]=R[siz]=siz;
else
{
R[siz]=R[H[r]];
L[R[H[r]]]=siz;
L[siz]=H[r];
R[H[r]]=siz;
}
}
void del(int c)
{
L[R[c]]=L[c];
R[L[c]]=R[c];
for(int i=D[c];i!=c;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 recover(int c)
{
for(int i=U[c];i!=c;i=U[i])
for(int j=L[i];j!=i;j=L[j])
++S[Col[U[D[j]]=D[U[j]]=j]];
L[R[c]]=R[L[c]]=c;
}
bool dancing(int d)
{
if(R[0]==0)
{
for(int i=0;i<d;i++)
str[(ans[i]-1)/16]=(ans[i]-1)%16+'A';
for(int i=0;i<16*16;i++)
{
cout<<str[i];
if(i%16==15)cout<<endl;
}
return true;
}
int c=R[0];
for(int i=R[0];i!=0;i=R[i])
if(S[i]<S[c])
c=i;
del(c);
for(int i=D[c];i!=c;i=D[i])
{
ans[d]=Row[i];
for(int j=R[i];j!=i;j=R[j])
del(Col[j]);
if(dancing(d+1))
return true;
for(int j=L[i];j!=i;j=L[j])
recover(Col[j]);
}
recover(c);
return false;
}
}dlx;
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0),cout.tie(0);
int t=0;
while(cin>>str)
{
if(t)
cout<<endl;
t++;
for(int i=1;i<=15;i++)
cin>>str+i*16;
dlx.init(16*16*16,16*16*4);
for(int i=0;i<16;i++)
for(int j=0;j<16;j++)
for(int k=1;k<=16;k++)
if(str[i*16+j]=='-' || str[i*16+j]=='A'+k-1)
{
dlx.push((i*16+j)*16+k,i*16+j+1);
dlx.push((i*16+j)*16+k,16*16+i*16+k);
dlx.push((i*16+j)*16+k,16*16*2+j*16+k);
dlx.push((i*16+j)*16+k,16*16*3+((i/4)*4+(j/4))*16+k);
}
dlx.dancing(0);
}
return 0;
}