9273:PKU2506Tiling
总时间限制:
2000ms
单个测试点时间限制:
1000ms
内存限制:
131072kB
描述
对于一个2行N列的走道。现在用1*2,2*2的砖去铺满。问有多少种不同的方式。
下图是一个2行17列的走道的某种铺法。
输入
整个测试有多组数据,请做到文件底结束。每行给出一个数字N,0 <= n <= 250
输出
如题
样例输入
2
8
12
100
200
样例输出
3
171
2731
845100400152152934331135470251
1071292029505993517027974728227441735014801995855195223534251
先去发现规律:
我们发现如果第n个是 一个 1 * 2 砖 竖着放 就是f(n - 1)种情况
如果第n 个是 1 * 2的砖横放就有 f(n-2)种情况
如果第n个是 2*2的砖也是 有f(n-2)种情况
然后递归方程和状态方程就出来了
f(n) = f(n-1) + 2 * f(n-2)
但是这个题的数很大我们用long long 也存不下,所以就需要大数存储,用到大数相加大数相乘。
然后写一下解题步骤
1)我们先确定状态方程(递归方程);
2)递归边界
3)运用大数相加
4)运用大数乘低精度
递归写法
#include<iostream>
#include<cstring>
using namespace std;
int dp[260][305];
int* Plus (int a[], int b[])
{
int i, k;
k = a[0] > b[0] ? a[0] : b[0];
for( i = 1;i <= k; i++)
{
a[i+1] += (a[i] + b[i]) / 10;
a[i] = (a[i] + b[i]) % 10;
}
if(a[k+1] > 0)
a[0] = k+1;
else
a[0] = k;
return a;
}
int* Multi(int a[],int key)//高精度 乘以低精度 a= a*key
{
int i,k;
if( key == 0)
{
memset(a, 0,sizeof(a));
a[0] = 1;
return 0;
}
for( i = 1;i <= a[0];i++)
a[i] = a[i] * key;
for( i = 1;i <= a[0]; i++)
{
a[i+1] += a[i]/10 ;
a[i] %= 10;
}
while(a[a[0] + 1] > 0) a[0] ++ ;
return a;
}
void give(int a[], int b[]){
for(int i = 0; i <= a[0]; i++){
b[i] = a[i];
}
}
int* DFS(int i){
if(dp[i][0] != 0)
return dp[i];
else{
int temp_1[305] = {0};
int temp_2[305] = {0};
give(DFS(i - 1), temp_1);
give(DFS(i - 2), temp_2);
give(Plus(temp_1, Multi(temp_2, 2)), dp[i]);
return dp[i];
}
}
int main(){
memset(dp, 0, sizeof(dp));
int n;
dp[0][1] = 1;
dp[0][0] = 1;
dp[1][1] = 1;
dp[1][0] = 1;
dp[2][0] = 1;
dp[2][1] = 3;
DFS(255);
while(cin >> n){
for(int i = dp[n][0]; i >= 1; i--)
cout << dp[n][i];
cout << endl;
}
return 0;
}
非递归写法
状态方程dp从下往上推一波
#include<iostream>
#include<cstring>
using namespace std;
int dp[260][305];
int main(){
memset(dp, 0, sizeof(dp));
int n;
dp[0][1] = 1;
dp[0][0] = 1;
dp[1][1] = 1;
dp[1][0] = 1;
dp[2][0] = 1;
dp[2][1] = 3;
for(int i = 3; i <= 255; i++){
int k = max(dp[i-1][0], dp[i-2][0]);
for(int j = 1; j <= k; j++){
dp[i][j] = dp[i-1][j] + dp[i-2][j] * 2;
}
dp[i][0] = k;
for(int e = 1; e <= k; e++){
int temp = dp[i][e] / 10;
dp[i][e] %= 10;
dp[i][e + 1] += temp;
}
if(dp[i][k + 1] != 0)
dp[i][0] = k + 1;
}
while(cin >> n){
for(int i = dp[n][0]; i >= 1; i--)
cout << dp[n][i];
cout << endl;
}
return 0;
}