題目:
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;
}