AcWing 291. 蒙德里安的梦想

状压dp 模板
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 12, M = 1<<11;

LL f[N][M];//状态表示(f[i][j],i表示第i列,j表示以二进制存储的从第i-1列插入的状态集合)
bool st[M];//预处理时判断是否为合法状态(是否有长度为奇数的子串0)

int main(){
    int n,m;
    while(cin>>n>>m,n&&m){
        for(int i=0;i < 1<<n;i++){//预处理st
            int cnt=0;
            bool flag=true;
            for(int j=0;j<n;j++){
                if(i>>j&1){
                    if(cnt&1){
                        flag=false;
                        break;
                    }
                    cnt=0;
                }
                else cnt++;
            }
            if(cnt&1) flag=false;
            st[i]=flag;
        }
        vector<int> state[1<<n];
        for(int i=0;i<1<<n;i++){
            for(int j=0;j<1<<n;j++){
                if((i&j)==0 && st[i|j]) state[i].push_back(j);//存储对应的合法状态
            }
        }
        memset(f,0,sizeof f);
        f[0][0]=1;//f[0][0]表示棋盘第1列中由第0列插入第1列的状态集合,(强行)算一个合法状态
        for(int i=1;i<=m;i++){//每次只能使第i-1列填充完所有合法状态,所以需要多判断一列
            for(int j=0;j<1<<n;j++){
                for(auto k:state[j]) f[i][j]+=f[i-1][k];
            }
        }
        cout<<f[m][0]<<endl;
    }
    
}

posted @ 2022-05-09 23:25  xhy666  阅读(35)  评论(0)    收藏  举报