[bzoj1087][scoi2005][DP][状态压缩]互不侵犯King

来源:互联网 发布:hbase删除一条数据 编辑:程序博客网 时间:2024/04/29 20:52

Description

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

Input

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

Output

方案数。

Sample Input

3 2

Sample Output

16

HINT

N,K ( 1 <=N <=9, 0 <= K <= N * N)

题解

嗯。最近学的状态压缩,一道不错的状态压缩题。我们开一个三维的dp数组。dp[i][j][k]表示第i行,第j个状态(二进制的j。0表示不放国王,1表示放国王),到目前共使用了k个国王(包括本行)的最多方案数。状态转移方程就是dp[i][j][k]=dp[i][j][k]+dp[i-1][l][k-sum[i]] (l表示上一行与j可以匹配的方案,sum[i]表示第i个状态的人数).
这样我们就可以开心地用状态压缩做啦~第一道自己ac的bzoj题,很开心~

代码

#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<iostream>using namespace std;typedef long long LL;LL f[11][(1<<11)+10][90];int bit[20];LL n,k,v[(1<<11)+10],vn;LL sum[1100];LL getsum(int x){    LL ret=0;    for(int i=1;i<=n;i++)if((bit[i]&x))ret++;    return ret;}int main(){    //freopen("king.in","r",stdin);freopen("king.out","w",stdout);    bit[1]=1;for(int i=2;i<=9;i++)bit[i]=bit[i-1]*2;    scanf("%d%d",&n,&k);    memset(f,0,sizeof(f));    int maxx=(1<<n)-1;vn=0;    for(LL x=0;x<=maxx;x++)    {        if(((x<<1)&x)==0)        {            sum[++vn]=getsum(x);            v[vn]=x;        }    }    memset(map,false,sizeof(map));    //for(int i=1;i<=vn;i++)for(int j=i+1;j<=vn;j++)if((v[i]&v[j])==0 && ((v[i]<<1)&v[j])==0 && ((v[i]>>1)&v[j])==0){map[i][j]=map[j][i]=true;}    for(int x=1;x<=vn;x++)f[1][v[x]][sum[x]]=1;    for(int i=2;i<=n;i++)        for(int p=1;p<=vn;p++)//当前第i行             for(int q=1;q<=vn;q++)//上一个i-1行                 if((v[p]&v[q])==0 && ((v[p]<<1)&v[q])==0 && ((v[p]>>1)&v[q])==0)                {                    for(int kk=sum[q];kk+sum[p]<=k;kk++)                    {                        f[i][v[p]][kk+sum[p]]+=f[i-1][v[q]][kk];                    }                }    LL ans=0;    for(int p=1;p<=vn;p++)ans+=f[n][v[p]][k];    printf("%lld\n",ans);    return 0;}
0 0
原创粉丝点击