在学习动态规划时的入门练习题,没有找到具体题目,不过觉得推导过程不错,记录一下
题目:
在一个3 X N的长方形方格中,铺满1X2的骨牌(骨牌个数不限制),给定N求方案数。
先降低一下难度,考虑 2 X N 的长方形方格
比如:N=2 时方案数为 2
如果是 N 的方案,怎么求?
第 n 列,我们可以竖着放 1 个,也可以把 n - 1 列拿来,横着放 2 个
骨牌长度=2,不会影响 n - 2 列,所以 n 列的方案等同于:
n - 1 列 + 竖放1个, 或者 n-2 列 + 横放 2个
类似于爬楼梯的情况,所以我们的推导公式:
f(n) = f(n-1) + f(n-2)
再来看初始值的推导
N=2,图示方案数=2,
N=1,只能竖放 1 个,所以方案数=1,那么 f(2) = f(1) + f(0) 就能得知 f(0) = 1
f[0] = 1;
f[1] = 1;
for(int i=2; i<= n; i++)
{
f[i] = f[i-1] + f[i-2];
}
再回到 3 X N 的长方形方格问题
我们可以得知在 N = 奇数的情况下,没有办法填充满,所以方案数 = 0
灰色部分是多余的格子,白色格子随意放置都能放满
这样我们就仅需要考虑 N = 偶数的情况
比如:N=2 时方案数为3。
颜色仅作为标识 1X2 的骨牌,无差异
那么 N = 4 的情况相当于 N = 2 的情况在扩展一个 N = 2
扩展的白色格子同之前一样,有 3 种方案,那么我们是否可以得出结论:
f(n) = 3 * f(2) ?
答案是否定的。当新的扩展出现时,老的格子内容就可能发生变化,比如:
如果单独来看相当于多了一块
我们需要用额外的方式来记录这类 多的方块组合
f[n] 是我们要求的答案,现在变为 f[n][0],即用二维数组的方式记录方案数
比如:
f[n][0] 表示没有多余方块
f[n][1] 表示多了 1 个方块
f[n][2] 表示多了 2 个方块
我们再来分别看这三类如何表示:
1. f[n][0] 可以看做 f[n-2][0] 基础上放 3个,f[n-1][1] 基础上放 1 个,f[n-2][2] 基础上放两个
f[n][0] = f[n-2][0] + f[n-1][1] + f[n-2][2];
2. f[n][1] 可以看做 f[n-1][2] 基础上放 1 个
f[n][1] = f[n-1][2];
3. f[n][2] 可以看做 f[n][0] 的基础上竖放 1 个,也可以看做 f[n-1][1]的基础上横放 2 个
f[n][2] = f[n][0] + f[n-1][1];
f[0][0] = f[1][1] = f[0][2] = 1;
for(int i=2; i<=n; i++)
{
f[i][0] = f[i-2][0] + f[i-1][1] + f[i-2][2];
f[i][1] = f[i-1][2];
f[i][2] = f[i][0] + f[i-1][1];
}