您的位置:首页 > 其它

【转载】数学游戏(mathgame)解题方法 - N皇后位运算解法,14皇后亦在1秒中

2016-08-08 09:31 357 查看
【转】桐桐的数学游戏(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

其中,关于本题解法的程序在(三)里面,试了一下,真的很厉害!连例程都不能比它好,而打表有时也比这还慢一点。亲自测试,发现13只用0.08秒左右,而14只用0.6秒,15只用2.8秒,是我见过的里面最快的。下面给出这位大神的程序(注:从Pascal翻译为C++,使用了GNU风格的缩进,请不要在意)
/*
本程序翻译自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);
}
像这样的样例程序,进一步的展示出了位运算的高效。当然,这个程序实际上思路也不难。大概就是首先如从第一行开始,第一行的所有位置依次枚举,而在枚举中造成了一些所谓的”禁位“,也就是再放下去会与已知的皇后冲突的地方。第二行就不能和第一行冲突,但显然不用考虑第三行,只用考虑该行上既不是与皇后1同列,也不在其两条对角线之一上的位置,并继续枚举这些可用位置。这,就是这个神奇程序的思想。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: