洛谷P1562 还是N皇后

题目描述

正如题目所说,这题是著名的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;
}

猜你喜欢

转载自blog.csdn.net/zsyzClb/article/details/84490191
今日推荐