bzoj1087: [SCOI2005]互不侵犯King 状压dp

Description

  在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。

Input

  只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

Output

  方案数。

题解

玉米田(轻击有惊喜)的解法一样。预处理一行所有合法情况。由于是四周的八个格子都不能有国王,在判断时多一个左移、右移,然后dp扫一遍

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=1e9;
const int maxn=(1<<9)+10;
typedef long long ll;
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,k;
int is[maxn];
ll f[10][maxn][90];
int main(){
    n=read();k=read();
    for(int i=0;i<(1<<n);i++){
        is[i]=((i&(i<<1))==0)&&((i&(i<<1))==0);
        if(is[i]){
            int num=__builtin_popcount(i);
            if(num>k)continue;
            f[1][i][num]=1;
        }
    }
    for(int i=2;i<=n;i++) for(int j=0;j<(1<<n);j++)
        if(is[j]){
            int num1=__builtin_popcount(j);
            for(int p=0;p<(1<<n);p++) if(((p&j)==0)&&((p&(j<<1))==0)&&((p&(j>>1))==0))
                for(int q=0;q<=k-num1;q++) f[i][j][q+num1]+=f[i-1][p][q]; 
        }
    ll ans=0;
    for(int i=1;i<=n;i++) for(int j=1;j<(1<<n);j++)
        if(is[j])ans+=f[i][j][k];
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/Nan-Cheng/p/9741583.html