当前位置:   article > 正文

蓝桥杯:国际象棋【状态压缩dp】_蓝桥杯状态压缩dp考的多吗

蓝桥杯状态压缩dp考的多吗

写了有五六道状态压缩dp的题,本菜发现这种题目其实和线性dp差不多,只不过是多了一个状态压缩,即将某个状态压缩到一串二进制中;

先看题:

 

因为行数很小,所以不难想到是状态压缩dp;

这道题和洛谷的炮兵阵地很像,都是一行的状态可以牵扯到上两个状态,所以我们在对i行进行状态转移方程的时候,我们得考虑第i-1和i-2行的状态,然后这道题目从某种意义上来说,比炮兵阵地要难一些,因为这个还有一个马的个数限制,所以我们得开4个维度的dp数组;

我们先明确一下,状态集合的定义,即dp数组的定义:

f[i][j][k][z]表示第i行的状态为j,i-1行的状态为k,且1~i行总共有z头马;

然后我们就可以想状态转移方程了,这个很简单,只要第i、i-1、i-2行互不干扰,那么我们就有:

【我们即第i行状态为j,i-1行状态为k,i-2行状态为z,且前1~i行总共有q头马,第i行的马有p头】

f[i][j][k][q]+=f[i-1][k][z][q-p]

这里记录一下自己踩的坑吧,本菜刚开始的时候是用了滚动数组优化的,但是这里本菜忘了一件事情:滚动数组在解决求方案数的dp中要初始化,即将之前用过的空间初始化,要不然会叠加以前计算过的状态;

但是最后本菜发现空间完全够用,所以就没用滚动数组优化了;

另外还有一个坑,那就是,如果我们发现i和i-1行冲突了,那么就不用枚举下去了,直接枚举i-1行的下一个状态,否则以下的循环会建立在i-1和i行冲突的基础之上,如果在状态转移的同一个循环里进行判断,那么不会影响结果,但会浪费大量的时间,甚至tle

那么接下来就是代码了:

  1. #include<iostream>
  2. #include<algorithm>
  3. #define ll long long
  4. using namespace std;
  5. const int N=110,M=1<<6,mod=1e9+7;
  6. struct p{
  7. int n=0;//棋子个数
  8. }st[M+10];
  9. ll f[N][M][M][21];//表示第i行状态为j,第i-1行状态为k的方案数,且有z头马的方案数
  10. int n,m,p;
  11. ll ans;
  12. void init(){//初始化每一个状态
  13. for(int i=0;i<1<<n;i++){
  14. for(int j=0;j<n;j++)
  15. if(i>>j&1) st[i].n++;
  16. }
  17. }
  18. bool jud(int i,int j){
  19. return ((i>>2)&j)||((i<<2)&j)||((j<<2)&i)||((j>>2)&i);
  20. }
  21. bool jud1(int i,int j){
  22. return ((i>>1)&j)||((i<<1)&j)||((j<<1)&i)||((j>>1)&i);
  23. }
  24. int main(){
  25. cin>>n>>m>>p;
  26. init();
  27. for(int i=0;i<1<<n;i++){//枚举第1行
  28. f[1][i][0][st[i].n]++;
  29. }
  30. for(int i=0;i<1<<n;i++){//枚举第2行
  31. for(int j=0;j<1<<n;j++){
  32. for(int k=0;k<=p;k++){
  33. if(st[j].n>k) continue;
  34. if(jud(i,j)) continue;
  35. f[2][j][i][k]+=f[1][i][0][k-st[j].n];
  36. }
  37. }
  38. }
  39. for(int i=3;i<=m;i++){//枚举每一行
  40. for(int j=0;j<1<<n;j++){//i->st
  41. for(int k=0;k<1<<n;k++){//i-1->st
  42. if(jud(j,k)) continue;
  43. for(int z=0;z<1<<n;z++){//i-2->st
  44. if(jud1(j,z)||jud(k,z)) continue;
  45. for(int q=0;q<=p;q++){
  46. if(st[j].n>q) continue;
  47. f[i][j][k][q]+=f[i-1][k][z][q-st[j].n]%mod;
  48. f[i][j][k][q]%=mod;
  49. }
  50. }
  51. }
  52. }
  53. }
  54. for(int i=0;i<1<<n;i++){
  55. for(int j=0;j<1<<n;j++){
  56. if(jud(i,j)) continue;
  57. ans+=f[m][i][j][p];
  58. ans%=mod;
  59. }
  60. }
  61. cout<<ans%mod;
  62. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/518641
推荐阅读
相关标签
  

闽ICP备14008679号