Find the number of ways to tile an m*n rectangle with long dominoes -- 3*1 rectangles.
Each domino must be completely within the rectangle, dominoes must not overlap (of course, they may touch each other), each point of the rectangle must be covered.
Input
The input contains several cases. Each case stands two integers m and n (1 <= m <= 9, 1 <= n <= 30) in a single line. The input ends up with a case of m = n = 0.
<p< dd="">
Output
Output the number of ways to tile an m*n rectangle with long dominoes.
<p< dd="">
Sample Input
3 3
3 10
0 0
<p< dd="">
Sample Output
2
28
题目大概:
用1*3的矩形把n*m的矩形放满,有多少种方法。
思路:
和第一个状态dp一样的题。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define ll long long
const int le=9;
ll dp[31][1<<le][1<<le];
int w,h;
int pan(int pos,int qian,int qian1)//判断状态是否合法
{
for(int i=pos;i<pos+3;i++)
{
if(!(qian&(1<<i))||!(qian1&(1<<i)))
return 0;
}
return 1;
}
void dfs(int pos,int st,int now,int qian,int qian1,ll sum)
{
if(pos==w)
{
dp[st][now][qian]+=sum;
return;
}
if(pos+3<=w&&pan(pos,qian,qian1))//横放
{
dfs(pos+3,st,now|(1<<pos)|(1<<(pos+1))|(1<<(pos+2)),qian,qian1,sum);
}
if(!(qian&(1<<pos))&&!(qian1&(1<<pos)))//竖放
{
dfs(pos+1,st,now|(1<<pos),qian|(1<<pos),qian1,sum);
}
if(qian1&(1<<pos))//不放
{
dfs(pos+1,st,now,qian,qian1,sum);
}
}
int main()
{
while(~scanf("%d%d",&w,&h)&&(w||h))
{
memset(dp,0,sizeof(dp));
dfs(0,1,0,(1<<w)-1,(1<<w)-1,1);
for(int i=2;i<=h;i++)//枚举行
{
for(int j=0;j<(1<<w);j++)//枚举每一个状态
{
for(int k=0;k<(1<<w);k++)//枚举上一行状态
{
if(dp[i-1][j][k])
dfs(0,i,0,j,k,dp[i-1][j][k]);
}
}
}
printf("%lld\n",dp[h][(1<<w)-1][(1<<w)-1]);
}
return 0;
}