AcWing 291. 蒙德里安的梦想

AcWing 291. 蒙德里安的梦想

题意:给出 (n<=11, m<=11)的矩阵,要求将矩阵全部恰好分成 (1 imes 2) 或者 (2 imes 1) 的小矩阵,问方案数。
题解:主要是dp数组的含义定义要了解,设 (dp_{i, j}) 表示的是第 (i)(j) 形状的方案数,这里的 (j) 代表的是二进制的状态。想象一个 (01) 串,然后在串中第 (x) 个0代表的是此列的第 (x) 行这个位置,是横着的,且是横着的第一个格子。是第一个格子,所以在 (i) 列,考虑 (i - 1) 列时,(j_{i-1}) 才可以与 (j_{i}) 进行 (|) 运算,然后 (1)(1) 之间的 (0) 的数量必须是偶数才合法。注意会爆 (long long).
代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 12;
ll dp[N][(1 << N)];
bool vis[N];
bool check(int x, int n) {
    int cnt = 0;
    int  d =0 ;
    while (x) {
        if (x & 1) {
            if (cnt % 2 != 0)return 0;
            cnt = 0;
        }
        else {
            cnt++;
        }
        d++;
        x /= 2;
       
    }
    if ((n - d + cnt) % 2 != 0)return 0;
    return 1;
}
void out(int x) {
    if (x == 0) cout << 0;
    while (x) {
        if (x & 1)cout << 1;
        else cout << 0;
        x /= 2;
    }
    return;
}
void solve() {
    int n, m;
    while (cin >> n >> m && n && m) {
        memset(dp, 0, sizeof dp);
        dp[0][0] = 1;
        int ans = 0;
        for (int i = 1; i <= m; i++) {
            for (int j = 0; j < 1 << n; j++) {
                for (int k = 0; k < 1 << n  ; k++) {
                    if ( (k & j) == 0  && check(j | k, n)) {//(k & j == 0)检查是否横格有冲突,check( j | k, n)检查是否竖格合法。
                        dp[i][j] += dp[i-1][k];
                    }
                }
               
            }
        }
        cout << dp[m][0] << endl;
    }
   
}
int main() {
    int t = 1;//cin >> t;
    while (t--) solve();
    return 0;
}
原文地址:https://www.cnblogs.com/Xiao-yan/p/14501433.html