acwing 291. 蒙德里安的梦想

状压dp板题

#include

using namespace std;
typedef long long ll;
const int N =12, M = 1<<12;


ll f[N][M]; ///代表前i-1列都被填满,j代表第i列的状态
bool st[M]; ///预处理每一种状态是否合法
int n, m;

int main()
{
    while(scanf("%d%d", &n, &m)&&(n+m))
    {
        for(int i = 0; i < (1<<n); ++i)
        {
            int c = 0; /// 记录连续0的个数
            st[i] = 1;
            for(int j = 0; j < n; ++j)
            {
                if(i>>j&1)
                {
                    if(c&1) st[i] = 0;
                    c = 0;
                }
                else c++;
                if(!st[i]) break;
            }
            if(c&1) st[i] = 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])  ///如果j和k没有冲突,且第i列的摆放不会使第i-1出现奇数的连续空格
                f[i][j] += f[i-1][k];
            }
        }
        printf("%lld\n", f[m][0]);
        
    }
    return 0;
}

你可能感兴趣的:(动态规划)