打表是最快的做法。退而求其次,直接搜就行了,注意下减枝即可。用DLX纯粹是为了套模板。
皇后问题的行列约束很容易转化成01矩阵的列,但对角约束却比较麻烦,因为可能不必完全满足:比如5*5的棋盘,有5行5列,这些要全部不重不漏的满足,但正对角线却有9条,而且只要不重就行了。反对角线亦然。
所以在每一步搜索的过程中,选择约束列的时候,只要选行约束的列和列约束的列就行了(第90行);结束的条件也由稀疏矩阵为空变成了行列约束为空(第85行)。
另外这个题非常无聊的一点是问过的问题可能还会再问,所以打表是必须的。
#include <cstdio>
#include <cstring>
static const int maxm = 1000, maxn = 600, maxnode = maxm*maxn;
int mat[maxm][maxn], N, m, n;
int pres[11];
int UU[maxnode], LL[maxnode], L[maxnode], R[maxnode], U[maxnode], D[maxnode];
int count[maxm+1], head, res;
void remove(int now){
int ll = LL[now];
for (int t = R[ll]; t != ll; t = R[t]){
L[R[UU[t]]] = L[UU[t]];
R[L[UU[t]]] = R[UU[t]];
for (int p = D[UU[t]]; p != UU[t]; p = D[p])
for (int q = R[p]; q != p; q = R[q]){
count[UU[q]]--;
D[U[q]] = D[q];
U[D[q]] = U[q];
}
}
}
void resume(int now){
int ll = LL[now];
for (int t = R[ll]; t != ll; t = R[t]){
L[R[UU[t]]] = UU[t];
R[L[UU[t]]] = UU[t];
for (int p = D[UU[t]]; p != UU[t]; p = D[p])
for (int q = R[p]; q != p; q = R[q]){
count[UU[q]]++;
D[U[q]] = q;
U[D[q]] = q;
}
}
}
void init(){
int tp = 0;
head = tp++;
for (int i = 0; i < n; ++i){
int now = tp++;
count[now] = 0;
UU[now] = U[now] = D[now] = now;
L[now] = L[head];
LL[now] = R[now] = head;
R[L[head]] = now;
L[head] = now;
}
for (int j = 0; j < m; ++j){
int now = tp++;
LL[now] = L[now] = R[now] = now;
U[now] = U[head];
UU[now] = D[now] = head;
D[U[head]] = now;
U[head] = now;
}
for (int i = 0; i < m; ++i){
for (int j = 0; j < n; ++j){
if (!mat[i][j]) continue;
int now = tp++;
int ll = i+n+1, uu = j+1;
U[now] = U[uu];
D[now] = uu;
D[U[uu]] = now;
U[uu] = now;
UU[now] = uu;
L[now] = L[ll];
R[now] = ll;
R[L[ll]] = now;
L[ll] = now;
LL[now] = ll;
++count[uu];
}
}
}
void dfs(){
if (R[head] > 2*N || R[head] == head) {
++res;
return;
}
int c = R[head];
for (int t = R[c]; t != head && t <= 2*N; t = R[t])
if (count[t] < count[c]) c = t;
for (int u = D[c]; u != c; u = D[u]){
remove(u);
dfs();
resume(u);
}
}
int main(){
memset(pres,-1,sizeof(pres));
while (scanf("%d", &N) && N){
if (pres[N] >= 0){
printf("%d\n", pres[N]);
continue;
}
memset(mat, 0, sizeof(mat));
memset(count, 0, sizeof(count));
memset(L,0,sizeof(L));
memset(R,0,sizeof(R));
memset(U,0,sizeof(U));
memset(D,0,sizeof(D));
res = 0;
m = N*N;
n = N*6-2;
for (int i = 0; i < N*N; ++i){
int r = i/N, c = i%N;
mat[i][r] = mat[i][c+N] = mat[i][r+c+N*2] = mat[i][r-c+N*5-2] = 1;
}
init();
dfs();
printf("%d\n", pres[N] = res);
}
return 0;
}