问题描述:
Description
Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his ‘toilet series’ (where he had to use his toilet paper to draw on, for all of his paper was filled with squares and rectangles), he dreamt of filling a large rectangle with small rectangles of width 2 and height 1 in varying ways.
Expert as he was in this material, he saw at a glance that he’ll need a computer to calculate the number of ways to fill the large rectangle whose dimensions were integer values, as well. Help him, so that his dream won’t turn into a nightmare!
Input
The input contains several test cases. Each test case is made up of two integer numbers: the height h and the width w of the large rectangle. Input is terminated by h=w=0. Otherwise, 1<=h,w<=11.
Output
For each test case, output the number of different ways the given rectangle can be filled with small rectangles of size 2 times 1. Assume the given large rectangle is oriented, i.e. count symmetrical tilings multiple times.
Sample Input
1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0
Sample Output
1
0
1
2
3
5
144
51205
大致题意:
有1*2和2*1的矩形。现在要填满一个N*M的大矩阵。问有多少种方式。
解题思路:
这个状态不太好找。
我们可以这样,横着的为1,竖着的矩形,上面一行为0,下面一行为1。
这样的话,第一行合法的状态必须有连续的偶数1。比如说11110.就代表2个横着的,最后一位竖放。
我们先把第一行的合法状态找到,那么第1行的0下面必须为1.这个状态我们可以用((j|k)==(1 << M)-1)来处理。
然后还要满足横放的1必须是连续的偶数。这个条件可以用ok(j&k)来处理。
ac代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
long long int dp[15][1<<11];
int N,M;
bool ok(int x) //判断是不是连续的偶数1.
{
int sum=0,i;
for(i=M;i>0;i--)
{
if(x&(1<<(i-1)))
sum++;
else if(sum&1)
return false;
}
if(sum&1)
return false;
return true;
}
int main()
{
int i,j,k;
while(cin>>N>>M && N+M!=0)
{
memset(dp,0,sizeof(dp));
if((N*M)&1)
{
cout<<"0"<<endl;
continue;
}
if(M>N) //让M为小的数
{
k=M+N;
M=k-M;
N=k-M;
}
for(i=0;i<(1<<M);i++)
{
if(ok(i))
dp[1][i]=1;
}
for(i=2;i<=N;i++) //枚举后面的行
{
for(j=0;j<(1<<M);j++) //i行的状态。
{
for(k=0;k<(1<<M);k++) //i-1行的状态。
{
if(((j|k)==(1<<M)-1) && ok(j&k))
{
dp[i][j]+=dp[i-1][k];
}
}
}
}
cout<<dp[N][(1<<M)-1]<<endl;
}
return 0;
}