n皇后问题(bitmask 优化)

description:

经典八皇后问题的拓展,有一个n*n的棋盘,问放n个皇后在棋盘中且都相不攻击的种数有多少。


analysis:

大的框架使用回溯搜索法,一行一行放置皇后。但是在确定当前皇后的摆放位置时,考虑两种优化。

第一种优化:

在确定当前行哪些格子可以放时,当然不能每次都重新考虑之前走过的所有皇后对该行产生的影响。一般都是要要采用一种递推的策略,而不是重复计算。

棋盘中放置一个皇后,实际上是确定了一个“米”字型的禁止放置区域,问题在于快速确定当前行中哪些格子在静止放置区域中。既然是采用一行一行的搜索方式,就要找到前一行的禁止放置位置与当前行的禁止放置位置的关系。

n皇后问题(bitmask 优化)_第1张图片

如图,注意到米字型的禁止区可以分解为三类 纵向攻击线,右斜向攻击线,和左斜向攻击线。每次考虑下一行实际上都是三类线沿着格子方向的一个衍生。这样就有了一种单调性,维护三个bitset,分别表示当前行中位于三类攻击线上的点的集合,则在下一行中的禁止放置位置就是由上一行的三类攻击线延伸得到。具体来说,假设第i行的三类点的集合分别为,col[i],L[i],R[i].且当前行在第j个位置放皇后,则 col[i+1]=col[i]&(1<>1, R[i+1]=(R[i]|(1<

第二种优化:

在得到了可行位置的bitset后,可以快速的找到里面为1的位置,而不是一位一位的枚举看是否等于1. 方法是用S&(-S) 的技巧。假设当前可行位置bitset是S,设S中最低位为1的值为j,则S&(-S)得到的是(1<

代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef long long LL;
const int INF = 1 << 30;
const int maxn = 200005;
int n;

//int bitcount(int S){return S?(S&1)+bitcount(S>>1):0;}

void solve(int cur,int col_attack,int r_attack,int l_attack,int & ans){  //当前行,直线集合,右斜线集合,左斜线集合,答案
    if(cur==n) {ans++;return;}

    int ok=((1<>1;
        int nl=(l_attack|i)<<1;
        solve(cur+1,ncol,nr,nl,ans);
        ok&=~i;
    }
}

int main()
{

    //freopen("C:\\Users\\admin\\Desktop\\in.txt", "r", stdin);
    //freopen("C:\\Users\\admin\\Desktop\\out.txt", "w", stdout);

    for(n=15;n<=18;++n){
        int ans=0;
        double start=GetTickCount();
        solve(0,0,0,0,ans);
        double end=GetTickCount();
        cout<

结果:

n皇后问题(bitmask 优化)_第2张图片




你可能感兴趣的:(搜索)