蒙德里安的梦想——状态压缩dp
这道题想写出来真恶心啊(起码对于现在的我来说)主要用的方法就是正确选择dp的状态表达,以及使用状态压缩把每一种状态用二进制的01式子表示出来。
目前碰到的状态压缩就是把一种状态抽象成0与1,以01式子的形式表示该状态。
对于这道题,我们可以先分析每一列的状态,然后遍历就得到了整张图的状态。
摆放方块的时候,先放横着的,再放竖着的。总方案数等于只放横着的小方块的合法方案数。
状态表达:f[i,j]表示为在前i-1列状态已经满足题意,第i-1向第i列突出的状态为j的所有方案数量。
状态计算:
既然第 i 列固定了,我们需要看 第i-2 列是怎么转移到到第 i-1列的(看最后转移过来的状态)。假设此时对应的状态是k(第i-2列到第i-1列伸出来的二进制数,比如00100),k也是一个二进制数,1表 示哪几行小方块是横着伸出来的,0表示哪几行不是横着伸出来的。它对应的方案数是 f[i−1,k]f[i−1,k] ,即前i-2列都已摆完,且从第i-2列伸到第i-1列的状态为 k 的所有方案数。
AcWing 291. 蒙德里安的梦想 - AcWing(详细题解)
每种正确的状态应该满足:
1.每一列都没有连续奇数个0(这样就可以保证每一列都可以放下竖着的小方块并且不留空隙)
2.第i-1列伸向第i列的状态以及第i-2列伸向i-1列的状态不会有矛盾的出现(不会有重叠的突起小方块)
所以我们先预处理出满足这两种条件的所有状态,然后再进行dp

1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=12,M=1<<N; 4 long long f[N][M]; 5 //f[i,j]表示在i-1列已经ok,并且i-1伸到i的状态为j的方案数量 6 vector<int> sta[M]; 7 bool st[M]; 8 9 10 int main() 11 { 12 int n,m; 13 while(~scanf("%d%d",&n,&m)&&(n||m)) 14 { 15 //先预处理满足一列没有连续奇数个0的所有状态 16 for(int i=0;i< 1<<n;i++) 17 { 18 int cnt=0,flag=1; 19 //cnt表示该状态连续0的个数,flag=1表示该状态没有连续奇数个0 20 for(int j=0;j<n;j++) //从上往下遍历这一列 21 { 22 if(i>>j &1) //在i状态中第j位是1(凸出来) 23 { 24 if(cnt&1) //有连续奇数个0 25 { 26 flag=0; 27 //该状态不满足 没有连续奇数个0 这一条件 28 break; //没必要再在这个状态上浪费时间 29 } 30 cnt=0; //有连续偶数个0,依然符合条件,继续循环判断 31 } 32 else cnt++; // i状态中第j位是0 33 } 34 //判断该列的最后一行的cnt是否为奇数 35 //举个例子,0001。 36 if(cnt&1)flag=0; 37 st[i]=flag; //记录一下某列如果状态为i,是否符合条件 38 } 39 40 //再预处理i-1与i-2伸出来的部分没有矛盾的状态 41 for(int j=0;j< 1<<n;j++) //i列的状态 42 { 43 sta[j].clear(); 44 for(int k=0;k< 1<<n;k++) //i-1列的状态 45 { 46 //(j&k)==0的意思是只有在i-1与i-2伸出来的部分不会重叠时 47 //我们才选择这个状态 48 //j|k的意思是 j状态与k状态合起来的i-1列到底有几个1 49 //因为st[]表示满足预处理1的状态,所以st[j|k]就是用来 50 //判断是否j|k的状态满足条件1 51 if((j&k)==0&&(st[j|k])) 52 sta[j].push_back(k); //满足两个条件就记录下来 53 } 54 } 55 56 //正式开始dp 57 memset(f,0,sizeof f); 58 f[0][0]=1; 59 for(int i=1;i<=m;i++) 60 for(int j=0;j< (1<<n);j++) 61 for(auto k:sta[j]) //选择满足条件的状态 62 f[i][j]+=f[i-1][k]; 63 64 65 printf("%lld\n",f[m][0]); 66 67 } 68 69 70 71 return 0; 72 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】