题意
给定一个 n×m 大小的长方形(1≤n,m≤11),求使用 1×2 大小的长方形铺满它有多少种方案
 思路
显然本题可以使用状态压缩 dp 解决
设计状态 dpi,j 表示放到第 i 行,且第 i 行状态为 j 的情况下的答案
j 用二进制表示第 k 个格子是否是竖着铺且靠上的那个格子
考虑转移
如果当前行状态 p 与上一行状态 q 取与运算结尾不为 0,那么显然 p,q 无法转移,因为 p,q 存在同一列的两个格子都是竖着铺且靠上的那个格子
同时,p,q 取或运算的结果意味着在当前行是被 1×2(即竖着放)的长方形覆盖的,那么剩余的格子就是被横着放的长方形覆盖的
由于是横着放的,那么其长度必定为偶数,否则就不合法
由此可以得到判断 p,q 直接转移合不合法的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | bool check(int x, int y) {     if ((x & y) != 0)     {         return false;     }     int tmp = (x | y) | (1 << m), last = -1, now = 0;     while (tmp)     {         if ((tmp & 1) == 1)         {             if (((now - last - 1) & 1) != 0)             {                 return false;             }             last = now;         }         tmp = tmp >> 1, now++;     }     return true; }
   | 
注意在判断时要特别判断最后一段 0 的长度是否为偶数,不能漏判
 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
   | #pragma GCC optimize(3, "Ofast", "inline") #include <bits/stdc++.h> namespace solution {     typedef long long LL;     const int MAXN = 12 + 5;     const int MAX2N = (1 << 12) + 5;     LL n, m;     LL dp[MAXN][MAX2N];     bool check(int x, int y)     {         if ((x & y) != 0)         {             return false;         }         int tmp = (x | y) | (1 << m), last = -1, now = 0;         while (tmp)         {             if ((tmp & 1) == 1)             {                 if (((now - last - 1) & 1) != 0)                 {                     return false;                 }                 last = now;             }             tmp = tmp >> 1, now++;         }         return true;     }     int main()     {         while (scanf("%lld%lld", &n, &m) != EOF && n != 0 && m != 0)         {             std::memset(dp, 0, sizeof(dp));             dp[0][0] = 1;             for (int i = 1; i <= n; i++)             {                 for (int j = 0; j < (1 << m); j++)                 {                     for (int k = 0; k < (1 << m); k++)                     {                         if (check(j, k))                         {                             dp[i][j] += dp[i - 1][k];                         }                     }                 }             }             printf("%lld\n", dp[n][0]);         }         return 0;     } } int main() {     solution::main();     return 0; }
   |