[ACM] HDU 1400 Mondriaan's Dream (状态压缩,长2宽1长方形铺满)
- 作者: 五速梦信息网
- 时间: 2026年04月04日 13:58
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
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!

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<br/> if(temp!=(1<<m)-1)<br/> return false;<br/> int cnt=0;<br/> temp=s1&s2;//两个状态且运算,必须连续的1都是偶数个<br/> for(int i=0;i<m;i++)<br/> {<br/> if((temp&(1<<i)))//第i位是1<br/> cnt++;<br/> else<br/> {<br/> if(cnt&1)<br/> return false;<br/> }<br/> }<br/> if(cnt&1)<br/> return false;<br/> return true;<br/>} void solve()
{memset(dp,0,sizeof(dp));<br/> int maxd=1<<m;<br/> for(int i=0;i<maxd;i++)//铺第一行<br/> if(ok(maxd-1,i))<br/> dp[1][i]++;<br/> for(int i=2;i<=n;i++)//铺第i行<br/> {<br/> for(int j=0;j<maxd;j++)<br/> {<br/> for(int k=0;k<maxd;k++)<br/> if(ok(j,k))<br/> dp[i][j]+=dp[i-1][k];<br/> }<br/> }<br/> ll ans=0;<br/> ans+=dp[n][maxd-1];//最后一行肯定都是1<br/> printf("%I64d\n",ans);<br/>} int main()
{while(scanf("%d%d",&n,&m)!=EOF)<br/> {<br/> if(!n||!m)<br/> break;<br/> if(n*m&1)//小方块的个数为奇数个,肯定不能铺满<br/> {<br/> printf("0\n");<br/> continue;<br/> }<br/> if(n<m)<br/> n=n^m,m=n^m,n=n^m;<br/> solve();<br/> }<br/> return 0;<br/>}
相关文章
-
[android] android 获取网络连接信息
[android] android 获取网络连接信息
- 互联网
- 2026年04月04日
-
[android] 百度地图开发 (一).申请AK显示地图及解决显示空白网格问题
[android] 百度地图开发 (一).申请AK显示地图及解决显示空白网格问题
- 互联网
- 2026年04月04日
-
[Android]使用Dagger 2进行依赖注入
[Android]使用Dagger 2进行依赖注入
- 互联网
- 2026年04月04日
-
[51CTO]给您介绍Windows10各大版本之间区别
[51CTO]给您介绍Windows10各大版本之间区别
- 互联网
- 2026年04月04日
-
[.NET] C# 知识回顾
[.NET] C# 知识回顾
- 互联网
- 2026年04月04日
-
[ PHP+jQuery ] ajax 多级联动菜单的应用:电商网站的用户地址选择功能 ( 二 )
[ PHP+jQuery ] ajax 多级联动菜单的应用:电商网站的用户地址选择功能 ( 二 )
- 互联网
- 2026年04月04日






