求把 N×MN×M 的棋盘分割成若干个 1×21×2 的的长方形,有多少种方案。
例如当 N=2,M=4N=2,M=4 时,共有 55 种方案。当 N=2,M=3N=2,M=3 时,共有 33 种方案。
如下图所示:
image.png

输入格式

输入包含多组测试用例。
每组测试用例占一行,包含两个整数 NN 和 MM。
当输入用例 N=0,M=0N=0,M=0 时,表示输入终止,且该用例无需处理。

输出格式

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

数据范围

1≤N,M≤111≤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


image.png

  1. //f[i,j] 表示已经将前i-1列摆好,且从i-1列伸到i列的状态是j的所有方案
  2. #include <iostream>
  3. #include <algorithm>
  4. #include <cstring>
  5. #include <vector>
  6. typedef long long LL;
  7. using namespace std;
  8. const int N = 12, M = 1 << N; //M:列的状态
  9. LL f[N][M];
  10. bool st[M];
  11. vector<int> state[M];
  12. int n,m;
  13. int main(){
  14. while (cin >> n >> m, n || m) {
  15. //判断列是否能塞满小方格(偶数个连续的空格)
  16. for (int i = 0; i < 1 << n; ++i) {
  17. int cnt = 0; //记录0个数
  18. bool isValid = true; //判断是否合法
  19. for (int j = 0; j < n; ++j)
  20. if (i >> j & 1) {
  21. if (cnt & 1) { //前面0个数为奇数
  22. isValid = false;
  23. break;
  24. }
  25. cnt = 0; //把cnt置为0
  26. }else cnt++;
  27. if (cnt & 1) isValid = false;
  28. st[i] = isValid;
  29. }
  30. //处理是否能从j状态转换为i状态
  31. for (int i = 0; i < 1 << n; ++i) {
  32. state[i].clear();
  33. for (int j = 0; j < 1 << n; ++j) {
  34. if ((i & j) == 0 && st[i | j])
  35. state[i].push_back(j);
  36. }
  37. }
  38. //f[0,0] 也是一种状态从,因为不存在-1列伸过来
  39. memset(f,0,sizeof f);
  40. f[0][0] = 1;
  41. for (int i = 1; i <= m; ++i) {
  42. for (int j = 0; j < 1 << n; ++j) {
  43. for (auto & k : state[j]) {
  44. f[i][j] += f[i-1][k];
  45. }
  46. }
  47. }
  48. cout << f[m][0] << endl;
  49. }
  50. return 0;
  51. }