一条街道上共有 n * 2 个 地块 ,街道的两侧各有 n 个地块。每一边的地块都按从 1 到 n 编号。每个地块上都可以放置一所房子。
现要求街道同一侧不能存在两所房子相邻的情况,请你计算并返回放置房屋的方式数目。由于答案可能很大,需要对 109 + 7 取余后再返回。
注意,如果一所房子放置在这条街某一侧上的第 i 个地块,不影响在另一侧的第 i 个地块放置房子。
示例 1:
输入:n = 1
输出:4
解释:
可能的放置方式:
- 所有地块都不放置房子。
- 一所房子放在街道的某一侧。
- 一所房子放在街道的另一侧。
- 放置两所房子,街道两侧各放置一所。
示例 2
输入:n = 2
输出:9
解释:如上图所示,共有 9 种可能的放置方式。
const int MOD = 1e9 + 7, MX = 1e4 + 1;
vector<long long> dp(MX);
int init = [](){
dp[0] = 1; //没有地块,空一种情况
dp[1] = 2; //一个地块,空和放置一个房子两种情况
for(int i = 2;i < MX;i++){
dp[i] = (dp[i-2] + dp[i-1]) % MOD;
}
return 0;
}();
class Solution {
public:
int countHousePlacements(int n) {
return (dp[n] * dp[n]) % MOD;
}
};
他要计算两排房子放置的方式数,实际上只需要计算一排房子的放置数,然后将结果平方即可。这时候思考的是如何列出状态转移方程,可以设置 i 为地块,用dp来储存前 i 个地块有几种不同的方法。对于第 i 个地块,只有两种可能,一种是放置房子,一种是不放置房子。当放置房子的时候,i - 1 个地块只能不放房子,既然第 i - 1个地块只有一种情况,而又已经确定了在这种情况下,第i个地块是只有放置房子一种情况,所以有dp[i-2]种放置方式。当第 i 个地块不放置房子的时候,这时候 i - 1个地块就有两种选择,放房子或者不放房子两种情况,在已经确定了第i个地块只能不放置房子,所以这时候有dp[i-1]种情况。
上面已经讨论了第i个地块的两种可能性,他们是互相独立的,互不干涉的,所以可以列出状态转移方程dp[i] = dp[i-2] + dp[i-1]。然后在调用函数前,由于1 <= n <= MX
,将前MX个的dp[i]进行初始化即可(实际上是MX + 1个,因为dp[0]虽然不在范围内,但是计算dp[i]的时候有用)。