BZOJ1087 [SCOI2005]互不侵犯King 状态压缩动态规划

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ1087


题意概括

  在n*n的棋盘上面放k个国王,使得他们互相无法攻击,问有多少种摆法。


题解

  dp[i][j][x]表示前i行,状态为j,总共放了x个国王的方案总数。

  然后简单的转移一下即可。

  当然这样要炸。

  只需要在这之前把每行的合法情况筛选一下即可,这样的情况总数不到100。

  然后就可以了。


代码

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
typedef long long LL;
const int S=(1<<9)+5;
int n,k;
int sit[S],bitsum[S],sz;
LL dp[11][S][100];
int cnt1(int x){
    int ans=0;
    while (x){
        ans+=x&1;
        x>>=1;
    }
    return ans;
}
int main(){
    scanf("%d%d",&n,&k);
    sz=0;
    for (int i=0;i<(1<<n);i++)
        if (!(i&(i<<1)))
            sit[++sz]=i,bitsum[sz]=cnt1(i);
    memset(dp,0,sizeof dp);
    dp[0][1][0]=1;
    for (int i=0;i<n;i++)
        for (int j=1;j<=sz;j++)
            for (int x=0;x<=k;x++){
                if (!dp[i][j][x])
                    continue;
                for (int y=1;y<=sz;y++)
                    if (!(sit[j]&sit[y])&&!(sit[j]&(sit[y]<<1))&&!((sit[j]<<1)&sit[y])&&x+bitsum[y]<=k)
                        dp[i+1][y][x+bitsum[y]]+=dp[i][j][x];
            }
    LL ans=0;
    for (int i=1;i<=sz;i++)
        ans+=dp[n][i][k];
    printf("%lld",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ1087.html