1. 程式人生 > >洛谷P1562 還是N皇后

洛谷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;
}