状态压缩dp,291. 蒙德里安的梦想

291. 蒙德里安的梦想 - AcWing题库

求把 N×M 的棋盘分割成若干个 1×2 的长方形,有多少种方案。

例如当 N=2,M=4 时,共有 5 种方案。当 N=2,M=3 时,共有 3 种方案。

如下图所示:

2411_1.jpg

输入格式

输入包含多组测试用例。

每组测试用例占一行,包含两个整数 N和 M。

当输入用例 N=0,M=0时,表示输入终止,且该用例无需处理。

输出格式

每个测试用例输出一个结果,每个结果占一行。

数据范围

1≤N,M≤11

输入样例:
1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0
输出样例:
1
0
1
2
3
5
144
51205

 解析:

状态压缩dp的状态压缩一词体现在将状态用二进制数来表示,将一个集合的状态压缩为一个二进制数

AcWing 291. 蒙德里安的梦想(《算法竞赛进阶指南》打卡活动) - AcWing

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 12, M = 1 << N;
int n, m;
LL f[N][M];
vectorstate[M];
bool st[M];

int main() {
	while (scanf("%d%d", &n, &m) != EOF) {
		if (n == 0 && m == 0)
			break;
		for (int i = 0; i < 1 << n; i++) {
			int cnt = 0;
			bool is_valid = true;
			for (int j = 0; j < n; j++) {
				if (i >> j & 1) {
					if (cnt & 1) {
						is_valid = false;
						break;
					}
					cnt = 0;
				}
				else cnt++;
			}
			if (cnt & 1)is_valid = false;
			st[i] = is_valid;
		}
		for (int i = 0; i < 1 << n; i++) {
			state[i].clear();
			for (int j = 0; j < 1 << n; j++) {
				if ((i & j) == 0 && st[i | j])
					state[i].push_back(j);
			}
		}
		memset(f, 0, sizeof(f));
		f[0][0] = 1;
		for (int i = 1; i <= m; i++) {
			for (int j = 0; j < 1 << n; j++) {
				for (auto k : state[j]) {
					f[i][j] += f[i - 1][k];
				}
			}
		}
		cout << f[m][0] << endl;
	}
	return 0;
}

你可能感兴趣的:(#,数位dp,状态压缩dp,动态规划)