[BZOJ1087][SCOI2005]互不侵犯king

来源:互联网 发布:剖腹产 知乎 编辑:程序博客网 时间:2024/04/30 05:27

提交地址
Description

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

Input

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

Output

方案数。

Sample Input

3 2
Sample Output

16

思路:状态压缩。这题和方格取数很像,只是加多一维就好了。设DP[i][x][k]为第i行一定用x状态(x表示一行的状态,为二进制数)
得出DP方程:DP[i+1][y][k+len[x]]+=DP[i][x]k
接下来就枚举i,x,k,最后枚举y。

代码如下

#include<cstdio>#include<cstring>#include<cstdlib>#include<iostream>#define LL long long using namespace std;LL v[510],f[10][1100][1100],n,m;LL a[510][510],b[510];LL number[510];int main(){    b[1]=1;for(int i=2;i<=9;i++)b[i]=b[i-1]*2;    scanf("%lld%lld",&n,&m);int maxx=(1<<n)-1;    memset(f,0,sizeof(f));memset(number,0,sizeof(number));int vn=0;    for(int i=0;i<=maxx;i++)    {     if(((i&(i>>1))==0)&&((i<<1)&i)==0)     {         for(int j=1;j<=n;j++)          if(b[j]&i)number[i]++;        vn++;v[vn]=i;        f[1][i][number[i]]=1;     }    }    for(int i=2;i<=n;i++)    {        for(int p=1;p<=vn;p++)        {            int x=v[p];            for(int q=1;q<=vn;q++)            {                int y=v[q];                if((x&y)==0&&((y<<1)&x)==0&&(((y>>1)&x)==0))                {                    for(int ki=number[y];ki+number[x]<=m;ki++)                      if(f[i-1][y][ki]>0)                       f[i][x][ki+number[x]]+=f[i-1][y][ki];                }            }        }    }    LL ans=0;    for(int i=1;i<=vn;i++)ans+=f[n][v[i]][m];    printf("%lld\n",ans);    return 0;}
0 0
原创粉丝点击