【转】
桐桐的数学游戏(mathgame)
【问题描述】
相信大家都听过经典的“八皇后”问题吧?这个游戏要求在一个8×8的棋盘上放置8个皇后,使8个皇后互相不攻击(攻击的含义是有两个皇后在同一行或同一列或同一对角线上)。
桐桐对这个游戏很感兴趣,也很快解决了这个问题。可是,他想为自己增加一点难度,于是他想求出n皇后的解的情况。你能帮助他吗?
【输入格式】
输入仅有一个数n(1≤n≤13),表示为n皇后问题。
【输出格式】
输出仅有一个数,表示n皇后时问题的解法总数。
【输入样例】
8
【输出样例】
92
这道问题想必也是非常经典的回朔问题了,但是到现在仍有不少人研究它。我在网上顺路寻找位运算的时候,找到了小时后大概五年级左右非常喜欢的一本书的作者Matrix67的一篇文章,现贴出链接如下:
位运算简介及实用技巧(一):基础篇: http://www.matrix67.com/blog/archives/263
位运算简介及实用技巧(二):进阶篇(1): http://www.matrix67.com/blog/archives/264
位运算简介及实用技巧(三):进阶篇(2): http://www.matrix67.com/blog/archives/266
位运算简介及实用技巧(四):实战篇: http://www.matrix67.com/blog/archives/268
像这样的样例程序,进一步的展示出了位运算的高效。当然,这个程序实际上思路也不难。大概就是首先如从第一行开始,第一行的所有位置依次枚举,而在枚举中造成了一些所谓的”禁位“,也就是再放下去会与已知的皇后冲突的地方。第二行就不能和第一行冲突,但显然不用考虑第三行,只用考虑该行上既不是与皇后1同列,也不在其两条对角线之一上的位置,并继续枚举这些可用位置。这,就是这个神奇程序的思想。/*
本程序翻译自Matrix67的博客上的Pascal程序,地址为:http://www.matrix67.com/blog/archives/266
感谢Matrix67大神!这一程序异常高效
本程序已在GCC 4.9.2 下编译通过,并已经AC本道例题
*/
#define _DUBUG
#include <cstdio>
using namespace std;
int upperlim;
unsigned long long int sum;
void NQueen(int row,int ld,int rd)
{
int pos,p;
if (row!=upperlim)
{
pos=upperlim & ~ (row | ld | rd); //对角线上的用过就禁止。。。。。。
while(pos!=0) //这个循环的循环次数应该是pos中1的个数
{
p=pos & -pos; //相当于取pos二进制位最后一个1
pos=pos-p; //用过了
NQueen(row+p,(ld+p)<<1,(rd+p)>>1); //标记不能用的列,斜线上不能用的位置向左/右移动
}
}
else
{
++sum;
}
}
int main()
{
#ifndef _DEBUG
freopen("mathgame.in","r",stdin);
freopen("mathgame.out","w",stdout);
#endif
int n;
scanf("%d",&n);
upperlim=(1<<n)-1; //upperlim=(2^n)-1
sum=0;
NQueen(0,0,0);
printf("%d\n",sum);
}