国王

https://loj.ac/problem/10170

题目描述

  在\(n\times n\)的棋盘上放\(k\)个国王,国王可攻击相邻的\(8\)个格子,求使它们无法互相攻击的方案总数。

思路

  这道题的\(n\)比较小,我们考虑直接把棋盘的一行压成一个数,那么如果这个位置放了棋子,这个数的二进制下的数为\(1\),否则为\(0\),我们可以先预处理处所有满足条件的行的数,在\(dp\)列,用\(f[i][S][k]\)表示第\(i\)行状态为\(S\),到目前位置共放\(k\)个棋子的方案数,那么\(S\)可以从不互相攻击的状态转移过来,直接\(dp\)即可。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int s[600],p[600];
ll f[11][500][110];
int main()
{
    int n,k,cnt=0;
    scanf("%d%d",&n,&k);
    for(int i=0;i<(1<<n);i++)
    {
        if(i&(i<<1))continue ;
        int sum=0;
        for(int j=0;j<n;j++)
            if(i&(1<<j))sum++;
        p[++cnt]=i;
        s[cnt]=sum;
    }
    f[0][1][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=cnt;j++)
            for(int l=s[j];l<=k;l++)
            {
                for(int r=1;r<=cnt;r++)
                    if(!(p[j]&p[r])&&!(p[j]&(p[r]<<1))&&!(p[j]&(p[r]>>1)))
                        f[i][j][l]+=f[i-1][r][l-s[j]];
            }
    long long ans=0;
    for(int i=1;i<=cnt;i++)
        ans+=f[n][i][k];
    printf("%lld\n",ans);
}

猜你喜欢

转载自www.cnblogs.com/fangbozhen/p/11844454.html