HLOJ489 bzoj1087 状压例题3 互不侵犯的king

题面

题目描述
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
输入格式
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
输出格式
一行,一个整数,表示答案。

题解

还是状态压缩裸题。
f[i][j][k]代表第i行的状态是k,已经放了j个king的答案。
我们先要考虑合法的状态。
因为king的攻击方式是八个方向各一个格子,所以我们可以得到,如果i&(i<<1)活着i&(i>>1)其中一个不为0,那么i这个状态就是不合法的。flag[i]=true表示合法
我们顺带预处理出状态i中有几个1的数组num[i]。

状态转移方程

f [ i ] [ j ] [ R ] = f [ i 1 ] [ j n u m [ L ] ] [ L ] (R&L==0)&&((R<<1)&L==0)&&((R>>1)&L==0)

code

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int num=0;
    char c=' ';
    bool flag=true;
    for(;c>'9'||c<'0';c=getchar())
    if(c=='-')
    flag=false;
    for(;c>='0'&&c<='9';num=num*10+c-48,c=getchar());
    return flag ? num : -num;
}
const int maxn=11;
int n,k,num[1<<maxn];
long long f[maxn][maxn*maxn][1<<maxn];
bool flag[maxn];
void yuchuli(){
    for(int i=0;i<1<<n;i++)
        if(!(i&(i<<1))){
            int count=0;
            flag[i]=true;
            for(int j=0;j<n;j++)
                if(i>>j&1)count++;
            num[i]=count;
            f[1][num[i]][i]=1;
        }
}
void dp(){
    for(int i=2;i<=n;i++)
        for(int j=0;j<=k;j++)
            for(int R=0;R<1<<n;R++)
                if(flag[R]&&num[R]<=j)
                    for(int L=0;L<1<<n;L++)
                        if(flag[L])
                            if((R&L)||((R<<1)&L)||((R>>1)&L))
                                continue;
                            else
                                f[i][j][R]+=f[i-1][j-num[R]][L];
}
int main(){
    n=read();k=read();
    yuchuli();
    dp();
    long long ans=0;
    for(int i=0;i<1<<n;i++)
        ans+=f[n][k][i];
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39670434/article/details/80343313
今日推荐