Mondriaan's Dream
Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 783 Accepted Submission(s): 506
![](https://i-blog.csdnimg.cn/blog_migrate/349a9ba91b1853d22c5510230230797d.gif)
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!
![](https://i-blog.csdnimg.cn/blog_migrate/f3f8b872ee5d88abae6590dc1d39f645.gif)
1 2 1 3 1 4 2 2 2 3 2 4 2 11 4 11 0 0
1 0 1 2 3 5 144 51205
解题思路:
如图:问铺满大举行一共有多少种方法。因为长宽最大11,可以状态压缩.
从第一行开始铺砖。
dp[ i ] [ j ] 定义为 第i行的状态为 j 一共有多少种方法 .
把小矩形用01状态表示,小矩形由两个正方形组成, 对于横着放的小矩形,左右两个正方形用11表示,对于竖着的小矩形,上下两个正方形用分别01表示。
第i行的状态s2与第i-1行的状态s1有关。
s1和s2满足两个条件:
1. s1 | s2 得到的数二进制每一位都是1 ,因为对于竖着放的 ,0|1肯定是1,横着放的都是11,相或也是11.
2. s1 & s2 得到的数连续的1是偶数个,注意0也是偶数。这个看图观察就可以了。
本题犯的错误:
1.
获取一个数x二进制的第i位是0或者1,用 if( x&(1<<i) ==1) 是不对的, 这句话的意思是,把x的二进制数除了第i位都设为0,第i位通过 &1,来判断是0或者1,但是得到的数不一定是1,是2的倍数,比如 0010 或者 0100.
2.
判断一个数x二进制的每一位是否等于1 ,假设有m位 , 直接用 if( x==1<<m)-1),不用每一位的判断,前者效率更高。
代码:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <string.h>
using namespace std;
#define ll long long
ll dp[12][1<<12];//dp[i][j]表示第i行状态为j有多少种方法
int n,m;
bool ok(int s1,int s2)
{
int temp=s1|s2;//两个状态或运算每一位都必须是1
if(temp!=(1<<m)-1)
return false;
int cnt=0;
temp=s1&s2;//两个状态且运算,必须连续的1都是偶数个
for(int i=0;i<m;i++)
{
if((temp&(1<<i)))//第i位是1
cnt++;
else
{
if(cnt&1)
return false;
}
}
if(cnt&1)
return false;
return true;
}
void solve()
{
memset(dp,0,sizeof(dp));
int maxd=1<<m;
for(int i=0;i<maxd;i++)//铺第一行
if(ok(maxd-1,i))
dp[1][i]++;
for(int i=2;i<=n;i++)//铺第i行
{
for(int j=0;j<maxd;j++)
{
for(int k=0;k<maxd;k++)
if(ok(j,k))
dp[i][j]+=dp[i-1][k];
}
}
ll ans=0;
ans+=dp[n][maxd-1];//最后一行肯定都是1
printf("%I64d\n",ans);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
if(!n||!m)
break;
if(n*m&1)//小方块的个数为奇数个,肯定不能铺满
{
printf("0\n");
continue;
}
if(n<m)
n=n^m,m=n^m,n=n^m;
solve();
}
return 0;
}