题目描述
正如题目所说,这题是著名的N皇后问题。
输入输出格式
输入格式:
第一行有一个N。接下来有N行N列描述一个棋盘,“*”表示可放“.”表示不可放。
输出格式:
输出方案总数
输入输出样例
输入样例#1:
4 **.* **** **** ****
输出样例#1:
1
这一道题和n皇后问题非常像,不同的是这一道题有些位置无法放置皇后,如果用搜索的话会超时,不过限制皇后的位置却为状态压缩(位运算)提供了契机
限制皇后的位置无非就是这3种情况:
1.地形限制(输入的限制)
2.行的限制(皇后会吃掉同行的皇后),这个其实可以忽略不计
3.列的限制(皇后会吃掉同列的皇后)
4.斜的限制(皇后会吃掉左斜和右斜的皇后)
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<queue>
#include<stack>
#include<map>
#include<cmath>
#include<string>
#include<set>
#include<ctime>
#define lowbit(x) x&-x
using namespace std;
inline int read(){
int x=0,f=0;char s=getchar();
while(!isdigit(s))f|=s=='-',s=getchar();
while( isdigit(s))x=(x<<1)+(x<<3)+s-48,s=getchar();
return !f?x:-x;
}
inline void print(int x){
if(x/10>0)print(x/10);
putchar(x%10+'0');
}
const int N=21;
int n,sta[N];//sta表示每一行的限制
int flag,ans;//flag表示n个1,ans记录结果
char st[N];//st输入的时候用
void dfs(int now,int zuo,int you,int k){
if(now==flag){ans++;return;}//如果放完了
int p,pos=flag&(~(now|zuo|you|sta[k]));//pos表示限制
while(pos){
p=lowbit(pos);//树状数组中的lowbit()可以求出第一个出现的1
pos^=p;//把1删掉
dfs(now|p,(zuo+p)<<1,(you+p)>>1,k+1);//左斜到下一行就会左移一位,右斜右移一位
//我也不知道为什么把(zuo+p)<<1改成(zuo|p)<<1会变慢
}
}
int main(){
//freopen("data.in","r",stdin);
//freopen("std.out","w",stdout);
n=read();flag=(1<<n)-1;
for(int i=1;i<=n;i++){
scanf("%s",st+1);getchar();
for(int j=1;j<=n;j++)
if(st[j]=='.')sta[i]|=(1<<(n-j));
}
dfs(0,0,0,1);
//now表示列的情况,zuo、you分别记录被斜边ban掉的行的情况,k表示第几行
print(ans);
return 0;
}