首页 > 代码库 > 刷题向》关于第一篇状压DP BZOJ1087 (EASY+)

刷题向》关于第一篇状压DP BZOJ1087 (EASY+)

  这是本蒟蒻做的第一篇状压DP,有纪念意义。

  这道题题目对状压DP十分友善,算是一道模板题。

  分析题目,我们发现可以用0和1代表每一个格子的国王情况,

  题目所说国王不能相邻放置,那么首先对于每一行是否合法的判断条件就出来了:就是对于情况X,如果X&(x<<1)==0,即为合法情况。

  同理这样我们就可以得出每一行对于上一行是否合法的条件:(x&y)==0&&(x&(y<<1))==0&&(x&(y>>1))==0

  得出这个结论之后就比较好处理了,枚举行数,当前行情况,上一行情况,以及国王个数情况。

  在对于国王的个数的处理时,不能只考虑上一行自己的国王情况,还要考虑在上一行的情况下,还能有多少国王,这点在对于国王个数的处理时解决。

  然后给出题目

escription

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

Input

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

Output

  方案数。

Sample Input

3 2

Sample Output

16
思路已经给出,
于是愉快的贴出代码
技术分享
 1 /************************************************************** 2     Problem: 1087 3     User: PencilWang 4     Language: C++ 5     Result: Accepted 6     Time:28 ms 7     Memory:8828 kb 8 ****************************************************************/ 9  10 #include<stdio.h>11 int n,k,num[1025];12 long long ans,f[10][100][1024];13 bool s[1025];14 int main()15 {16     scanf("%d%d",&n,&k);17     int ass=1<<n;18     for(int i=0;i<ass;i++)19     {20         if((i&(i<<1))==0)21         {22         int x=i,sb=0;23         while(x){sb+=(x&1);x>>=1;}24         num[i]=sb;s[i]=true;25         f[1][num[i]][i]=1;26         }27     }28     for(int i=1;i<n;i++)29         {30         for(int x=0;x<ass;x++)31             {32             if(s[x])33             for(int y=0;y<ass;y++)34                 {35                 if(s[y])36                     {37                     if((x&y)==0&&((x>>1)&y)==0&&((x<<1)&y)==0)38                         for(int z=num[x];z+num[y]<=k;z++)39                             f[i+1][z+num[y]][y]+=f[i][z][x];40                     }41                 }42             }43         }44     for(int i=0;i<ass;i++)45     {46     ans+=f[n][k][i];47     }48     printf("%lld",ans);49     return 0;50 }51 
1087

 

刷题向》关于第一篇状压DP BZOJ1087 (EASY+)