来源:http://zju.acmclub.com/index.php?app=problem_title&id=1&problem_id=1059
1059:贴瓷砖分数: 1
标签
题目描述
有一块大小是 2 * n 的墙面,现在需要用2种规格的瓷砖铺满,瓷砖规格分别是 2 * 1 和 2 * 2,请计算一共有多少种铺设的方法。
输入格式
输入的第一行包含一个正整数T(T<=20),表示一共有T组数据,接着是T行数据,每行包含一个正整数N(N<=30),表示墙面的大小是2行N列。
输出
输出一共有多少种铺设的方法,每组数据的输出占一行。
样例输入
3
2
8
12
样例输出
3
171
2731
提示[+]
*** 提示已隐藏,点击上方 [+] 可显示 ***
当n=1时,显然只有一种铺设方法。
当n=2时,可以用2个竖的3*1瓷砖铺设,也可以用1个竖的3*2瓷砖铺设,故共有两种铺设方案。
当n=3时,
1) 用3个竖的3*1瓷砖铺设
2) 先用1个竖的3*1,再用1个竖的3*2瓷砖铺设
3) 先用1个竖的3*2,再用1个竖的3*1瓷砖铺设
4) 用1个3*3的瓷砖铺设
5) 用3个横的3*1瓷砖铺设
6) 先用1个横的3*1,再用一个横的3*2瓷砖铺设
7) 先用1个横的3*2,再用一个横的3*1瓷砖铺设
共7中方案
那么推广到一般情况(n>4),记铺设3*n墙壁总方案数为f(n).
1) 如果先铺3*1的墙壁,铺设3*1的方案数为1,还剩下3*(n-1)的墙壁的总方案数位为f(n-1),故这种情况共有有1*f(n-1)种方案。
2) 如果先铺3*2的墙壁,铺设3*2的方案数为1(因为要去掉与1)中重复的情况),还剩下3*(n-2)的墙壁的总方案数为f(n-2),故这种情况共有有1*f(n-2)种方案。
3) 如果先铺3*3的墙壁,铺设3*3的方案数为4(去掉与(1),(2)重复的情况),还剩下3*(n-3)的墙壁的总分数为f(n-3),故这种情况共有有4*f(n-3)种方案。
所以可以得出递推式f(n)=f(n-1)+f(n-2)+4*f(n-3);(n>=4)
先贴上我超时的dfs代码(乱的不成样子了,估计也只有我自己知道什么意思):
#include<iostream>
#include<cstring>
using namespace std;
int dir[2][3][2]={
{{0,0},{1,0},{2,0}},
{{0,0},{0,1},{0,2}}
};
int map[3][55],n,p=0,a[10];
long long count=0;
void dfs(int x,int y,int step){
if(x<0||x>=3||y<0||y>=n)
return ;
if(!step){
count++;
return ;
}
if(!map[x][y]){
for(int i=0;i<5;i++){
if(!i&&!x){
bool flag=true;
for(int j=0;j<3;j++)
if(map[x+dir[i][j][0]][y+dir[i][j][1]])
flag=false;
if(flag){
if(3==step){
count++;
return ;
}
for(int j=0;j<3;j++)
map[x+dir[i][j][0]][y+dir[i][j][1]]=-1;
if(x*y<2*(n-1)){
int tempx=x,tempy=y+1;
if(tempy>=n){
tempx++;tempy=0;
}
dfs(tempx,tempy,step-3);
}
for(int j=0;j<3;j++)
map[x+dir[i][j][0]][y+dir[i][j][1]]=0;
}
}
if(i==1&&(y+2)<n){
bool flag=true;
for(int j=0;j<3;j++)
if(map[x+dir[i][j][0]][y+dir[i][j][1]])
flag=false;
if(flag){
if(3==step){
count++;
return ;
}
for(int j=0;j<3;j++)
map[x+dir[i][j][0]][y+dir[i][j][1]]=-1;
int tempx=x,tempy=y+3;
if(tempy>=n){
tempx++;tempy%=n;
}
if(tempx<3&&tempy*tempx<=2*(n-1)){
dfs(tempx,tempy,step-3);
}
for(int j=0;j<3;j++)
map[x+dir[i][j][0]][y+dir[i][j][1]]=0;
}
}
if(i==2&&!x&&(y+1)<n){
bool flag=true;
for(int k=0;k<2;k++)
for(int j=0;j<3;j++)
if(map[x+dir[0][j][0]][y+dir[0][j][1]+k])
flag=false;
if(flag){
if(6==step){
count++;
return ;
}
for(int k=0;k<2;k++)
for(int j=0;j<3;j++)
map[x+dir[0][j][0]][y+dir[0][j][1]+k]=-1;
if(x*y<2*(n-1)-1){
int tempx=x,tempy=y+2;
if(tempy>=n){
tempx++;tempy%=n;
}
dfs(tempx,tempy,step-6);
for(int k=0;k<2;k++)
for(int j=0;j<3;j++)
map[x+dir[0][j][0]][y+dir[0][j][1]+k]=0;
}
}
}
if(i==3&&x<2&&y+2<n){
bool flag=true;
for(int k=0;k<2;k++)
for(int j=0;j<3;j++)
if(map[x+k+dir[1][j][0]][y+dir[1][j][1]])
flag=false;
if(flag){
int tempx=x,tempy=y+3;
if(tempy>=n){
tempx+=2;tempy%=n;
}
if(6==step){
count++;
return ;
}
if(tempx<3&&tempy*tempx<=2*(n-1)){
for(int k=0;k<2;k++)
for(int j=0;j<3;j++)
map[x+k+dir[1][j][0]][y+dir[1][j][1]]=-1;
dfs(tempx,tempy,step-6);
for(int k=0;k<2;k++)
for(int j=0;j<3;j++)
map[x+k+dir[1][j][0]][y+dir[1][j][1]]=0;
}
}
}
if(i==4&&!x&&(y+2)<n){
bool flag=true;
for(int k=0;k<3;k++)
for(int j=0;j<3;j++)
if(map[k+x+dir[1][j][0]][y+dir[1][j][1]])
flag=false;
if(flag){
if(9==step){
count++;
return ;
}
int tempx=x,tempy=y+3;
if(tempy>=n){
tempx++;tempy%=n;
}
if(tempx<3&&tempy*tempx<=2*(n-1)){
for(int k=0;k<3;k++)
for(int j=0;j<3;j++)
map[x+k+dir[1][j][0]][y+dir[1][j][1]]=-1;
dfs(tempx,tempy,step-9);
for(int k=0;k<3;k++)
for(int j=0;j<3;j++)
map[x+k+dir[1][j][0]][y+dir[1][j][1]]=0;
}
}
}
}
}
}
int main(){
while(cin>>n){
count=0;
memset(map,0,sizeof(map));
dfs(0,0,3*n);
cout<<count<<endl;
}
return 0;
}
#include<iostream>
using namespace std;
long long dp[51],n;
int main(){
dp[1]=1,dp[2]=2; dp[3]=7;
for(int i=4;i<=50;i++)
dp[i]=dp[i-1]+dp[i-2]+4*dp[i-3];
while(cin>>n)
cout<<dp[n]<<endl;
return 0;
}