题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1563
题目大意:在h*w的矩阵里铺满1*3的小矩阵,共有多少种方法
Sample Input
3 3
3 10
0 0
Sample Output
2
28
分析:状态压缩DP,跟ZOJ 1100 及其相识,不过那道题目使用1*2的木板平铺,题解链接:http://www.cnblogs.com/acm-bingzi/p/3289994.html
但是不能照搬这道题目的方法,3^9约等于20000,两次循环的话会超时,所以每次只找符合条件的状态。
每个格子有三种状态0,1,2, 0----横放或者竖放的第三个格子 对下层没有影响,1----竖放的中间那个格子 对下一层有影响,2----竖放的第一个格子 对下两层有影响。
dp[i][j]表示到第i层状态为j的方法数。
代码如下:
# include<stdio.h>
# include<string.h>
# include<math.h>
# define LL long long
LL dp[][];
int h,w; //高度、宽度
int zt,row; //状态、行数
int pos[],dig[];
void init()
{
pos[] = ;
for(int i=; i<=; i++)
pos[i] = pos[i-]*;
} void get() //得到该状态3进制下的各个位上的数字
{
int s=zt,len = ;
memset(dig,,sizeof(dig));
while(s)
{
dig[len++] = s%;
s = s/;
}
} void dfs(int col,int s) //这一行状态s受zt的影响,col表示列,作为标记
{
if(col==w) //当到达最大宽度时,需要运算
{
dp[row][s] += dp[row-][zt];
return;
}
if(dig[col]==) //上一层是0
{
if(col+<w && dig[col+]== && dig[col+]==) //横着放,下一层为0
dfs(col+,s);
dfs(col+,s+*pos[col]); //竖着放,下一次为2
}
else if(dig[col]==) //上一层为1时下一层只能为0
dfs(col+,s);
else
dfs(col+,s+pos[col]); //上一层为2时下一层只能为1
} int main()
{
init();
while(scanf("%d%d",&w,&h),h+w)
{
if((h*w)%) //这种情况下无论如何也不能填满
{
printf("0\n");
continue;
}
memset(dp,,sizeof(dp));
dp[][] = ;
for(row=; row<=h; row++)
for(zt=; zt<pos[w]; zt++)
{
if(dp[row-][zt])
{
get();
dfs(,);
}
}
printf("%lld\n",dp[h][]);
}
return ;
}