铺砖问题

题目:

Description
用1×2的 砖头铺满N*M的区域,不能有重叠,一共有多少种方案?如下图所示:



 
Input
一行输入N和M
Output
输出方案数mod (10^9+7)的值
Sample Input
2 2
Sample Output
2
Data Constraint
20%的数据满足1<=N,M<=6

50%的数据满足1<=N<=100,1<=M<=11

另外50%的数据满足1<=N<=10^200,1<=M<=5

题解:

50分状压DP。

设fi,j表示第i行,状态为j的方案数。

所谓状态为j,即为是否是竖着放的(覆盖到i+1行当前列),是为1,不是为0。

举个例子。
               _ __ _
第一行:|  |__|  |
第二行:|_|__|_|

对于第一行来说,状态为1001,因为第一列、第三列突到下面去了。
对于第二行来说,状态为0000

初始化很显然就是f0,0=1;

接下来谈转移。

设k表示第i-1的状态。

对于j(第i行的状态)来说,k要满足什么条件才合法呢?

First:(j and k)==0     因为同一列两个都为1就重复覆盖了。(c++的注意,位运算的优先级基本都低于比较)

Second: (j or k)二进制中连续的0必须要有偶数个。
例如k=1001 j=0100就显然不合法。
而(j or k)=1001的合法,(j or k)=1010的不合法。 (j or k)=1111的合法。
有一点要注意的是,如果(j or k)的二进制不够m位,就要在前面补0补齐m位。

枚举i(1~n),j(0~2^m-1),k(0~2^m-1),
如果k合法,那么f[i][j]+=f[i-1][k]; 
注意取模

最后的答案显然是fn,0,因为第n行不可以竖着放突下去。

这样就可以40分。超时一个点。

如果要50分,需要加点优化。

预处理对于j来说合法的k。

可以减少很多运算次数。





<think>好的,用户需要关于C++中问题的三级难度解决方案或示例代码。首先,我需要明确问题的具体定义。问题通常指用特定形状的块(如1x22x1)覆盖一个给定的区域,计算有多少种不同的。三级难度可能涉及较大的矩阵尺寸或更复杂的动态规划优化。 接下来,我应该考虑常见的解决方。这类问题通常使用动态规划(DP),尤其是当区域是二维的时候。经典的问题如多米诺骨牌满棋盘的问题,可以用状态压缩DP来解决。用户提到的三级难度可能要求处理更大的n,或者需要更高效的空间优化方。 然后,我需要回忆相关的算实现。状态压缩DP中,状态通常用二进制表示当前行的设情况,逐行转移状态。例如,当处理n×m的网格时,可以用一个二维数组dp[i][state]表示第i行状态为state时的方案数。状态转移需要考虑当前行和上一行的块排列情况,避免重叠和空隙。 用户可能需要示例代码,因此我需要构建一个C++的示例。考虑到三级难度,代码可能需要处理较大的n和m,比如n=10或更大,这时候普通的递归或暴力搜索会超时,必须用动态规划优化。例如,使用滚动数组来节省空间,或者预处理状态转移的可能情况。 另外,需要注意块的排列方式。如果是1x22x1块,那么状态转移时要考虑横向和纵向的设。对于每一行,状态表示当前行哪些位置已经被覆盖,哪些位置需要由下一行的竖来覆盖。状态转移时需要确保当前行和上一行的状态兼容,即上一行未覆盖的位置必须由当前行的竖填补。 可能还需要考虑一些边界条件,比如n或m为0的情况,或者当n*m为奇数时直接返回0,因为1x2块无覆盖奇数面积的区域。此外,预处理状态转移表可以加快DP的速度,避免在每一步都重新计算可能的状态转移。 在代码结构方面,可能需要一个循环遍历每一行,然后遍历所有可能的状态组合,计算每个状态下的方案数。使用位运算来高效处理状态的每一位,判断是否有冲突或未覆盖的位置。 最后,验证示例代码的正确性,比如在小规模的输入下(如2x2的区域,应该有2),确保代码输出正确结果。同时,测试较大输入时的运行时间,确保算效率符合三级难度的要求。 总结下来,步骤包括:定义状态表示,设计状态转移方程,优化空间复杂度(如滚动数组),处理边界条件,编写代码并进行测试。用户可能需要详细的注释来理解代码逻辑,因此代码中的注释也很重要。</think>### 问题解析 问题的核心在于用动态规划处理状态压缩,通过位运算表示块覆盖状态。以下是三级难度实现的关键步骤: 1. **状态定义** 使用二进制位表示每列的覆盖状态,例如`dp[i][mask]`表示第$i$行设完成后状态为`mask`的方案数,其中`mask`的二进制位1表示该位置需要下一行竖填补 2. **状态转移** 通过DFS方式枚举当前行和下一行的所有合组合,确保: - 当前行横向块不越界 - 下一行竖能覆盖当前行空缺 - 相邻行之间无重叠 3. **滚动数组优化** 使用`dp[2][1<<N]`交替存储状态,将空间复杂度从$O(M \cdot 2^N)$优化为$O(2^N)$ ### 三级难度C++示例代码 ```cpp #include <iostream> #include <cstring> using namespace std; long long tileFilling(int n, int m) { if ((n * m) % 2 != 0) return 0; if (n < m) swap(n, m); // 优化:保持较小维度作为状态位数 const int MAX_STATE = 1 << m; long long dp[2][MAX_STATE]; int *cur = dp[0], *next = dp[1]; memset(cur, 0, sizeof(dp[0])); cur[0] = 1; for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { memset(next, 0, sizeof(dp[0])); for (int mask = 0; mask < (1 << m); ++mask) { if ((mask >> j) & 1) { next[mask & ~(1 << j)] += cur[mask]; // 竖 } else { if (j < m-1 && !(mask & (1 << (j+1)))) // 横 next[mask | (1 << (j+1))] += cur[mask]; next[mask | (1 << j)] += cur[mask]; // 留空给下一行 } } swap(cur, next); } } return cur[0]; } int main() { cout << "2x2区域:" << tileFilling(2,2) << endl; // 输出2 cout << "3x4区域:" << tileFilling(3,4) << endl; // 输出11 return 0; } ``` [^1] ### 算特性 | 维度 | 说明 | |--------|-----------------------------| | 时间复杂度 | $O(N \cdot M \cdot 2^M)$ | | 空间复杂度 | $O(2^M)$ 滚动数组优化 | | 适用场景 | 棋盘类覆盖问题(最大处理15x15规模)|
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值