题目链接:http://soj.sysu.edu.cn/1121
题目大意:求用 2 * 1 的矩形拼成 3 * n(0 <= n <= 30)的矩形的方案数。下图是一个3 * 12的实例
解题思路:动态规划。首先根据题意我们可以知道,当 n 为奇数时,3 * n为奇数,即所得的矩形面积为奇数,而用 k 个小矩形拼凑而成的矩形所得面积为 2 * 1 * k,是偶数,故当n为奇数时,是无法找到这样的构造方案的,即其方案数为 0。接下来考虑偶数的情况,当 n = 2 时,共有三种情况,如下图
图1
假设用f(n)表示大矩形另一边长为 n 时总共的方案数。
当 n = 4时,其可以有左边的3*2矩形和右边的3 * 2矩形组成,那么共有 3 * 3 = 9中情况,但是还有哦其他两种情况,如下图,故当n = 4时,其总共有11种情况。
图2
当n = 6时,其可以(1)由左边的 3 * 4矩形和右边的3 * 2矩形组成,此时有f(4) * f(2) = 11 * 3 = 33,但是,这只是对矩形的一种划分,当把矩形划分为(2)左边3 * 2右边3 * 4时,对右边而言,其相比(1)的情况,只是多了图2 的两种情况,因此此时有 f(2) * 2 = 3 * 2 = 6种情况。此外,还可以把矩形作为一个大整体,则又有图3两种情况。因此当n = 6时,其总共有 f(4) * f(2) + f(2) * 2 + 2 = 33 + 6 + 2 = 41种情况
图3
依次类推,当求n时,可以依次把矩形划分为 (1)3 * (n - 2)和 3 * 2的矩形,(2)3 * (n - 4)和3 * 4 的矩形,(3)3 * (n - 6)和 3 * 6 的矩形,······和一个大整矩形
然后对每种情况求解相对前面几种划分没有出现的新增的方案数,即(1)f(n - 2) * f(2), (2)f(n - 4) * 2(因为这种分法相对(1)的分法右边的矩形只是新增了两种,而左边的矩形可以f(n - 4)种,根据乘法定理,可知新增了 f(n - 4) * 2种方案),(3)f(n - 6) * 2,······,2。然后依次把这些数相加即可得到总的方案数。
用动态转移方程就是:f(n) = f(n - 2) * f(2) + f(n - 4) * 2 + f(n - 6) * 2 + f(n - 8) * 2 +... + f(2) * 2 + 2
至此,本题基本可以求解了,只是有一种情况需要注意,就是当n = 0时,输出应该是 1 而不是 0,至于为什么我至今也没想明白,哪天想明白了再回来补充。
#include <iostream>
using namespace std;
int main()
{
int dp[35], n;
while (1)
{
cin >> n;
if (n == -1)
break;
if (n % 2 == 1)
{
cout << "0" << endl;
continue;
}
dp[0] = 1;
dp[2] = 3;
for (int i = 4; i <= n; i += 2)
{
dp[i] = dp[i - 2] * dp[2];
for (int j = i - 4; j >= 0; j -= 2)
dp[i] += dp[j] * 2;
}
cout << dp[n] << endl;
}
}