NOIP专题复习(二) 八皇后与各种优化

以八皇后为例来复习一下常见的几种搜索优化方法。
讲真,我觉得,位运算优化的八皇后就是一道状压DP…
luoguP1219


朴素算法

八皇后的核心是c[n]数组,表示第n行在第c[n]个位置。
然后枚举一下1~n-1行即可。
另一大关键是如何判断对角线,也很简单,|c[n]-c[x]|=|n-x|

#include <bits/stdc++.h>
using namespace std;
#define MAXN 14
int c[MAXN],cnt,n;
void print(){
    for(int i=1;i<=n;++i){
        cout<<c[i]<<" ";
    }
    cout<<endl;
}
bool check(int x){
    for(int i=1;i<x;++i){
        if((c[x]==c[i])||(c[x]-c[i]==x-i)||c[x]-c[i]==i-x) return false;
    }
    return true;
}
void dfs(int k){
    if(k==n+1) {
        ++cnt;
        if(cnt<=3)print();
        return;
    }
    for(int i=1;i<=n;++i){
        c[k]=i;
        if(k==1||check(k)) dfs(k+1);
    }
}
int main(){
    cin>>n;
    dfs(1);
    cout<<cnt<<endl;
    return 0;
} 

这样会T一个点。


分支界定优化

不妨多开两个数组,分别维护两个方向对角线的信息。
这样可以减少判断次数。


剪枝优化

考虑这个棋盘是具有对称性的。
因此,对k皇后,
如果k是偶数,那么我们可以只搜索第一行的一半,从而减少运算量。
如果k是奇数,以n=13为例
1)第一行[1,6]与[8,13]是对称的。
2)如果第一行放在第7个上,那么显然对于下一行,1)的分法是适用的,并且由于下一行不能放在第7个上,所以可以这样枚举。
相当于减少了一半枚举数量。


位运算优化

用dp[i][j]表示第i行的状态为j。这里的j是一个整数,其各个位表示的是某一格点是否存皇后。
比如,dp[5][173(10101101)]表示第5行时1、3、4、6、8列已经放过。
用rd,ld,row维护状态的转移。考虑一下,如果两个皇后在同一竖直线,那么显然下一行左边一个位置、右边一个位置与正下的位置都是不合理的。所以状态就可以转移了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <bitset>
using namespace std;
typedef long long LL;
LL ans,n,upperlim,qwq[14];
void print(){
    for(int i=1;i<=n;++i) cout<<qwq[i]<<" ";
    cout<<endl;
}
void dfs(LL ld,LL h,LL rd,int f){
    if(h!=upperlim){
        LL pos=upperlim & ~(ld|h|rd);
        while(pos){
            LL p=pos&-pos;
            pos-=p;
            if(ans<=3){
                LL tmp=p;
                while(tmp) tmp>>=1,qwq[f]++;
                dfs((ld+p)<<1,h+p,(rd+p)>>1,f+1);
                qwq[f]=0;
            }
            else dfs((ld+p)<<1,h+p,(rd+p)>>1,f+1);
        }
    }else {
        ++ans;
        if(ans<=3) print();
    }
}
int main() {
    cin>>n;
    upperlim=(1<<n)-1;
    dfs(0,0,0,1);
    cout<<ans<<endl;
}

参考:http://blog.csdn.net/hackbuteer1/article/details/6657109
luogu题解区各位神犇

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值