题目大意:给出一个n*n的一个棋盘,要求在这个棋盘上放置n个皇后。这个棋盘上的‘*’表示此处不能放置皇后,但不会影响皇后的攻击。问这样的棋盘,放置n个皇后有多少种放法
解题思路:因为n最多为15,所以可以用一个数表示每一行的状态。设置一个数组statu,记录刚开始每行能放置的状态,刚开始时能放置的位为0,不能放置的位为1。接下来一行一行枚举,回溯。dfs函数有四个参数,row,col,left,right
row:第几行
col:第row行的状态,1表示不能放,0表示可以放
left和right分别表示左斜线和右斜线的状态,还是0表可放,1表不可放
接下来将这个状态用“|”运算符结合起来,就可以得到该行的限制了,接着对这个限制进行取反运算"~",将0和1的状态表示替换一下,1表可放,0表不能放。
接着枚举可以放置的点,也就是找寻这个状态量中为1的点,从右往左找,这里有一个技巧,用这个状态量&(这个状态量-1再取反后的状态)&msk就可以得到最右边的1了。这里的msk主要是为了消除那些多余出来的列
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 20
char str[maxn];
int statu[maxn], n, msk;
int dfs(int row, int col, int left, int right) {
if(row == n)
return 1;
int ans = 0;
int cur = ~(statu[row] | col | left | right);
int last = cur&(-cur)&msk;
while(last) {
ans += dfs(row+1, col | last, (left | last) << 1, (right | last) >> 1);
cur ^= last;
last = cur&(-cur)&msk;
}
return ans;
}
int main() {
int mark = 1;
while(scanf("%d", &n) == 1 && n) {
msk = (1 << n) - 1;
for(int i = 0; i < n; i++) {
scanf("%s", str);
statu[i] = 0;
for(int j = 0; j < n; j++)
if(str[j] == '*')
statu[i] |= (1 << j);
}
printf("Case %d: %d\n",mark++, dfs(0,0,0,0));
}
return 0;
}