1、B站视频链接:E31 状态压缩DP 蒙德里安的梦想_哔哩哔哩_bilibili #include <bits/stdc++.h> using namespace std; const int N=12,M=1<<N; bool st[N];//st[i]存储合并列的状态i是否合法 long long f[N][M];//f[i][j]表示摆放第i列,状态为j时的方案数 int main(){ int n,m; while(cin>>n>>m,n||m){ //预处理:判断合并列的状态i是否合法 //合并列即两列状态合并之意,对应后面的st[j|k] //如果合并列的某行是1表示横放,是0表示竖放 //如果合并列不存在连续的奇数个0,即为合法状态 for(int i=0;i<1<<n;i++){//枚举状态 st[i]=true; int cnt=0; //记录合并列中连续0的个数 for(int j=0;j<n;j++){//n为行数,即状态的位数 if(i>>j&1){//如果i是1 if(cnt&1){//如果连续0的个数是奇数 st[i]=false;break; } }else{ cnt++;//如果是0,记录0的个数 } } if(cnt&1)st[i]=false;//处理高位0的个数 } memset(f,0,sizeof f); f[0][0]=1; for(int i=1;i<=m;i++){//阶段:枚举列 for(int j=0;j<1<<n;j++){//状态:枚举第i列的状态 for(int k=0;k<1<<n;k++){//状态:枚举第i-1列的状态 if((j&k)==0&&st[j|k]){//两列状态兼容:不出现重叠的1,不出现连续的奇数个0 f[i][j]+=f[i-1][k]; } } } } printf("%lld\n",f[m][0]);//第m列不横放即答案 } return 0; }