291. Mondrian's Dream (detailed explanation of state compression dp)

Find out how many ways there are to divide the N×M chessboard into several 1×2 rectangles.

For example, when N=2, M=4, there are 5 schemes in total. When N=2, M=3, there are 3 schemes.

As shown below:

input format

The input contains sets of test cases.

Each set of test cases occupies a line and contains two integers N and M.

When the input use case N=0, M=0, it means that the input is terminated, and this use case does not need to be processed.

output format

Each test case outputs a result, and each result occupies one line.

data range

1≤N,M≤11

Input sample:

1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0

Sample output:

1
0
1
2
3
5
144
51205

Problem-solving ideas:

The question is to consider whether the wooden blocks are placed horizontally or vertically. We can use dfs to search violently, but this will time out.

At this time, we can only consider one situation. When we only place wooden blocks placed horizontally, the other spaces must be placed vertically. This is how the total can be calculated.

When we see m<12, it is simpler for us to use binary numbers.

State compression:

Represent 3 states in binary

store state as a decimal number

1. Use 1 to indicate horizontal placement and nothing can be placed in the next column, and use 0 to indicate vertical placement.

2. We arrange them in columns. There cannot be consecutive odd numbers of 0s in each column, because the presence of odd numbers of 0s means that the vertical placement is not satisfied (a vertical placement in a column requires two 0s).

3. Considering the relationship between row i and row i-1, this is the meaning of dynamic programming, and recursion is performed.

For example; line i-1 is 1001 and line i can be 0110. At this time, compatibility needs to be considered.

When the i-1 column and the i-th column & are 0, that is, when they have no conflict, when the second case is judged. It just satisfies the meaning of the question.

problem solving code

#include<bits/stdc++.h>
using namespace std;
const int N = 12, M = 1 << N;
int n, m;
long long f[N][M];
bool st[M];

int main() {
	while (cin >> n >> m, n | m) {
		for (int i = 0; i < 1 << n; i++) { // n位  n - 1个
			int cnt = 0;
			st[i] = true;
			for (int j = 0; j < n; j++) {
				if (i >> j & 1) {
					if(cnt & 1 ) // 如果连续得0得个数位奇数是    这是因为竖放得位置个数要为2
					st[i] = false;
				}
				else {
					cnt++;
				}
			}
			// 处理最高为的0的个数
			if (cnt & 1) st[i] = false; 
		}

		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列的状态和 i-1是否兼容
				for (int k = 0; k < 1 << n; k++) { // i -l
					if ((j & k) == 0 && st[j | k])
					{ // j|k 是兼容后不出现奇数个相邻的0
						f[i][j] += f[i - 1][k];
					}
				}
			}
		}
		cout << f[m][0] << endl;
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/zhi6fui/article/details/128560419