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;}