AcWing 291. Mondrian's dream

Title: Mondrian's dream

Link :( Mondrian's dream) [ https://www.acwing.com/problem/content/293/ ]

The meaning of problems: seeking the N * M board 1 is divided into a plurality of rectangular * 2, how many kinds of programs.
For example when N = 2, when 4 M =, a total of 5 kinds of programs, when N = 2, M = 3, the total of three kinds of programs

Analysis:
1. When all placed sideways rectangular good, then the rectangle is disposed vertically method only
2.f [i, j] denotes the i-th column when placed in the state that all the i-th row j of Scheme , j denotes the i-th - 1 block column to the extended state of the i th column
3. vertically empty rectangular block is used to place 1 * 2, and therefore requires an even number of consecutive empty squares, we can pre-out can be placed
4. how to properly transfer? First, not conflict, f [i - 1, k ] denotes place the first i - 1 time, k is the i - 2 column extending to i - 1 is a block
so in order to avoid conflicts, to be placed in a length of 2 rectangular, k & j must be zero, a row in a column of a block can be placed
5 an odd number of 0 can not be continuously present, in order to display a rectangular vertically

#include <cstring>
#include <cstring>
#include <iostream>

using namespace std;

const int n = 12;
const int m = 1 << 12;//第二维状态最大有2^12种可能

typedef long long ll;
bool st[m];//state,预处理好的状态
ll f[n][m];

int main()
{
    int n, m;
    while (scanf("%d%d", &n, &m), n || m) {
        //预先处理好状态,在DP过程中直接判断
    
        for (int i = 0; i < 1 << n; ++i) {
            st[i] = true;//先设置好每个状态为1
            int cnt = 0;//统计连续0的个数
            for (int j = 0; j < n; ++j) {//判断每一位是否为0
                if (i >> j & 1) {//判断之前已经累计好的0个数为奇数
                    if (cnt & 1)
                        st[i] = false;//为奇数,设置为false
                    cnt = 0;//重新累计0的个数
                }
                else {
                    ++cnt;//没碰到1,就累计0的个数
                }               
            }
            if (cnt & 1)
                st[i] = false;//如果最后的是连续的0,没有碰到1,就需要再判断一下
        }
        
        memset(f, 0, sizeof f);
        f[0][0] = 1;
        for (int i = 1; i <= m; ++i) {//m + 1列,多计算m + 1列
            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]) {
                        f[i][j] += f[i - 1][k];
                    }
                }
            }
        }

        printf("%lld\n", f[m][0]);

    }
    
    return 0;
}

Guess you like

Origin www.cnblogs.com/pixel-Teee/p/11965634.html