luoguP1562 还是N皇后-状态压缩、位运算优化搜索

题目大意:八皇后变成14皇后,加了不能放的区域。

参考题解

  • 逐行放置皇后,首先排除每行有多个皇后互相排斥的情况

  • 用二进制表示状态.1表示该点不能放(与其他位置的皇后排斥或初始状态就不能放).0表示该点可以放皇后

  • 用map[]来存储初始状态,将'.'位 置为1

  • dfs保存四个参数:当前列的状态,从左上到右下对角线的状态,从右上到左下对角线的状态,当前为第几行

  • 获取当前哪一位可以放置皇后:将四者取并集(即将四者进行或运算).得到的状态中为1的就可以放置皇后.

  • 用树状数组中的lowbit()就可以得到从右向左的第一个1

  • 将状态中的1减掉,继续找下一个1

  • 更新"将是下一行的状态",由于对角线是斜着影响的,所以左上到右下对角线的状态需要左移一位,右上到左下对角线的状态需要右移一位.

  • 知道当n个皇后都放下时候,ans++;


#include <iostream>
#include<stdio.h>
using namespace std;
int n,ans,End,map[20];
void dfs(int row,int ld,int rd,int d) { //row列,ld右斜 ,d行
	if(d>n) { //if(row==End)
		ans++;return;
	}
	int pos=End&(~(row|ld|rd|map[d])),p;
	while(pos) {
		p=pos&(-pos);//找到第一个非零位置。
		pos-=p;

		dfs(row+p,(ld+p)<<1,(rd+p)>>1,d+1);//ld+p右移,左斜线不能再用, rd+p右斜,d+1,下一行;
	}
}
int main() {
	char s[20];
	int i,j,k;
	scanf("%d\n",&n);
	End=(1<<n)-1;
	for(i=1; i<=n; i++) {
		gets(s);
		for(j=1; j<=n; j++)
			map[i]=(s[j-1]=='.')+(map[i]<<1);
	}
	dfs(0,0,0,1);
	printf("%d",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lengxuenong/article/details/79345975