Mondriaan's Dream (POJ-2411, DP)

1. Title link:

POJ-2411

2. The main idea of ​​the topic:

There is a chessboard of n*m size, filled with wooden blocks of size 2*1, and ask how many different methods are there.

3. Analysis:

First of all, make one thing clear: only need to count the number of legal schemes of horizontally placed wooden blocks. For a legally horizontally placed wooden block, only insert the blanks in the vertical position, and the number of schemes is one.

Let dp[i][j] denote the number of plans in which columns 1~i-1 have been placed horizontally and the state of column i is j.

The state j in the i-th column refers to the binary state representation of the wooden block placed in the i-1th column extending to the i-th column.

As shown in the figure above, the state j of the i-th column is 1110010.

Let the state of column i-1 be k.

An easy-to-obtain legal state transition relationship should meet the following two conditions:

① (j & k) == 0, to ensure that two horizontally placed wooden blocks will not cross.

② (j | k) There cannot be an odd number of consecutive 0s, which ensures that the vertical wooden block can fill the space.

For the second point, we can preprocess which states are legal.

The time complexity is O(4^{n}m)

4. Code implementation:

#include <cstdio>
#include <cstring>
using namespace std;

typedef long long ll;

const int M = (int)11;

bool valid[(1<<M) + 5];
ll dp[M + 5][(1<<M) + 5];

void init(int n)
{
    for(int i = 0; i < (1<<n); ++i)
    {
        bool have_odd = 0, cnt = 0;
        for(int j = 0; j < n; ++j)
        {
            if((i>>j) & 1)
                have_odd |= cnt, cnt = 0;
            else
                cnt ^= 1;
        }
        valid[i] = !(have_odd | cnt);
    }
}

int main()
{
//    freopen("input.txt", "r", stdin);
    int n, m;
    while(~scanf("%d %d", &n, &m) && (n + m))
    {
        init(n);
        memset(dp, 0, sizeof(dp));
        dp[0][0] = 1;
        for(int i = 1; i <= m; ++i)
        {
            for(int j = 0; j < (1<<n); ++j)
            {
                for(int k = 0; k < (1<<n); ++k)
                {
                    if(!(j & k) && valid[j | k])
                    {
                        dp[i][j] += dp[i - 1][k];
                    }
                }
            }
        }
        printf("%lld\n", dp[m][0]);
    }
    return 0;
}

 

Guess you like

Origin blog.csdn.net/The___Flash/article/details/104107895