题目
题目来源
题目描述
有两种形状的瓷砖:一种是 2 x 1 的多米诺形,另一种是形如 “L” 的托米诺形。两种形状都可以旋转。
给定整数 n ,返回可以平铺 2 x n 的面板的方法的数量。返回对 10^9 + 7 取模 的值。平铺指的是每个正方形都必须有瓷砖覆盖。两个平铺不同,当且仅当面板上有四个方向上的相邻单元中的两个,使得恰好有一个平铺有一个瓷砖占据两个正方形。
我的解法与讲解(动态规划)
二维数组解
dp[i][4] 代表的是第i列的状态,dp[i][0]代表这一列上下都没有被铺,1代表上面一块没有没铺,2代表下面一块没有被铺,3代表上下全被铺满。
dp[i]的状态只与dp[i-1]的状态有关
0->0与3->3会多考虑一种,所以要去掉其中之一。据此可做出转移方程
int numTilings(int n){
long dp[n + 1][4];
long MOD = 1000000007;
dp[1][0] = 1;
dp[1][1] = 0;
dp[1][2] = 0;
dp[1][3] = 1;
for(int i = 2; i <= n; i++){
dp[i][0] = (dp[i - 1][3]) % MOD;
dp[i][1] = (dp[i - 1][0] + dp[i - 1][2]) % MOD;
dp[i][2] = (dp[i - 1][0] + dp[i - 1][1]) % MOD;
dp[i][3] = (dp[i - 1][0] + dp[i - 1][3] + dp[i - 1][2] + dp[i - 1][1]) % MOD;
}
return (int)dp[n][3];
}
优化
空间优化
c语言好像不能直接拷贝数组,其它语言可用两个一维数组替代二维数组,一个数组存储
最优解
dp[i]代表0到i列铺满的方法数量。
递推:0 ~ n-1列铺好,加个多米诺推到n;0 ~ n-2列铺好,就是n-1没铺好,不能是两个竖着的多米诺,只能是两个横着的多米诺。我们在通过dp(i)平铺dp(n)时,i+1~n-1列不能有完成拼好的,否则就重复计算了。
0 ~ n-3列铺好推到n,说明倒数三列状态都不能是3。就是两个L型的托米诺,
dp(n-4) 两个托米诺夹一个多米诺
dp(n-5) 两个托米诺夹两个多米诺
…….
托米诺是能倒过来的,所以有托米诺的就会有两种情况。
由此推出公式dp(n) = dp(n-1) + dp(n-2)+2*(dp(n-3)+dp(n-4)+dp(n-5)……dp(1));
得到dp(n-1)=dp(n-2)+dp(n-3)+2*(dp(n-4)+dp(n-5)+……dp(1));
将两式相减得到dp(n)=2*dp(n-1)+dp(n-3);
int numTilings(int n){
if(n <= 2){
return n;
}
long dp[n+1];
dp[1] = 1;
dp[2] = 2;
dp[3] = 5;
long MOD = 1000000007;
for(int i = 4; i <= n; i++){
dp[i] = (2 * dp[i - 1] + dp[i - 3]) % MOD;
}
return (int)dp[n];
}