求把 N×MN×M 的棋盘分割成若干个 1×21×2 的的长方形,有多少种方案。
例如当 N=2,M=4N=2,M=4 时,共有 55 种方案。当 N=2,M=3N=2,M=3 时,共有 33 种方案。
如下图所示:
输入格式
输入包含多组测试用例。
每组测试用例占一行,包含两个整数 NN 和 MM。
当输入用例 N=0,M=0N=0,M=0 时,表示输入终止,且该用例无需处理。
输出格式
数据范围
输入样例:
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

//f[i,j] 表示已经将前i-1列摆好,且从i-1列伸到i列的状态是j的所有方案#include <iostream>#include <algorithm>#include <cstring>#include <vector>typedef long long LL;using namespace std;const int N = 12, M = 1 << N; //M:列的状态LL f[N][M];bool st[M];vector<int> state[M];int n,m;int main(){while (cin >> n >> m, n || m) {//判断列是否能塞满小方格(偶数个连续的空格)for (int i = 0; i < 1 << n; ++i) {int cnt = 0; //记录0个数bool isValid = true; //判断是否合法for (int j = 0; j < n; ++j)if (i >> j & 1) {if (cnt & 1) { //前面0个数为奇数isValid = false;break;}cnt = 0; //把cnt置为0}else cnt++;if (cnt & 1) isValid = false;st[i] = isValid;}//处理是否能从j状态转换为i状态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);}}//f[0,0] 也是一种状态从,因为不存在-1列伸过来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;}
