瓷砖覆盖地板问题

jeiwt 2010-06-21 04:36:35
具体见《编程之美》4.2节扩展问题

具体题目描述见百度文库
http://wenku.baidu.com/view/8eafcac789eb172ded63b780.html


简单说即是:
瓷砖规格为 1 * 2,不允许切割瓷砖

要求用该瓷砖铺 n * m (n*m必为偶数)的地板,有多少种铺法?


-----------------------------------------------

简单的2 * m的地板,用1*2的瓷砖铺法有:

f(m)为所求

f(1) = 1;
f(2) = 2;

f(m) = f(m-1) + f(m-2); (m > 2)


如用1*2瓷砖铺8*8的地板, 有多少种铺法?
...全文
1073 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
pmars 2010-06-27
  • 打赏
  • 举报
回复
状态dp
FancyMouse 2010-06-27
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 jeiwt 的回复:]
这个能具体点吗?
怎么个状态dp?
谢谢~


引用 4 楼 fancymouse 的回复:
这个当n,m其中有一个比较小的时候可以状态压缩dp。否则的话就麻烦了。
压以后复杂度基本是2^(3m)*log(n)
[/Quote]把一列的状态压缩起来,2^m个状态。转移方程可以写成这2^m个状态的线性组合的形式,因此就是个2^m * 2^m的矩阵的乘法。程序算出这个矩阵以后用那个常规技巧做矩阵幂次就可以做到2^(3m)*log(n)了。
qq120848369 2010-06-27
  • 打赏
  • 举报
回复
书上讲的挺明白啊,看看就行了.
zyl072 2010-06-27
  • 打赏
  • 举报
回复
这个题在POJ上有,地址是:http://acm.pku.edu.cn/JudgeOnline/problem?id=2411
以前做过这个题,是用状态DP来做的。大致说下方法,DP需要用到两维,一维表示到达哪一行,另一维表示这一行的状态。

用二进制来表示
假定方格为N行M列。
表示方法如下:
f[i][j]。 ---- i表示第i行,j表示该行的二进制状态。而f[i][j]则记录由i,j构成的状态有多少种摆法。

我举个例子,假定总共有4行5列。
如下状态: *号表示被铺了方块,0表示尚未被铺方块。
*****
*0**0
00000
00000
可以看到第2行的状态为*0**0,即用二进制来表示就是10110,即 f[2][22] 来表示。(当然,行号也可以从0开始计)

以上是状态表示方法,有了状态表示方法以后就需要得到一个进行状态转移的递推式。
考虑i行j列的那个格子,有3种状态,第一种是由第i-1行j列铺上来,第二种是 在本行内,与相邻的格子铺的瓷砖,第三种该格子留空,以备下一行来使用。
枚举这一行的格子的每一种状态,即可以得到所需的上一行状态。

举例来说,枚举一个如下状态(*表示该格子是已经被填充的,-表示空格子,其余数字均表示2*1的瓷砖摆法):

1***3**
1-22344

可知本行的状态为 1011111,生成该状态所需要的上一行状态为,0111011。因为只有这样才能满足瓷砖1和瓷砖3的嵌入且又不会留下空格子。

因此可以由本状态进行一次累加:用二进制表示第二维 即 a[i][1011111] += a[i-1][0111011]。

那么,最后 a[N][(1<<M)- 1]即为所得。

POJ的这题的代码(几年前写的,风格很烂,见笑了):

#include <stdio.h>
#include <string.h>

long long s[14][14][5000];
int w,h;
int list[20],v[20];

void GetList(int step){
if (step>w){
int value1=0;
int value2=0;
int i;
for (i=1;i<=w;i++){
value1<<=1;
value2<<=1;
switch (list[i]){
case 0:
value1|=1;
break;
case 1:
value1|=1;
value2|=1;
break;
case 2:
value2|=1;
break;
}
}
if (h>1)
s[w][h][value2]+=s[w][h-1][value1];
else
s[w][h][value2]=1;
return;
}
if (h>1) list[step]=2,GetList(step+1);
if (step<w) list[step]=list[step+1]=1,GetList(step+2);
list[step]=0;
GetList(step+1);
}


int main(){
memset(s,0,sizeof s);
int i,j,k;
v[0]=1;
for (i=1;i<20;i++)
v[i]=v[i-1]<<1;
for (w=1;w<=12;w++)
for (h=1;h<=12;h++)
GetList(1);
for (scanf("%d%d",&w,&h);w;scanf("%d%d",&w,&h))
printf("%I64d\n",s[w][h][v[w]-1]);
}


2953784 zyl072 2411 Accepted 7844K 124MS G++ 1222B 2007-11-29 10:22:08

有点需要说明,由于这题的测试数据很多,因此我不是每次输入后重新计算,而是选择了一次性把所有可能输入的结果全部算完。。然后再输入后就可以直接输出结果。这样做在测试数据很多的情况下可以避免很多重复运算。因此我的DP状态是用三维来表示的,分别是 行、列、当前行状态。
zenny_chen 2010-06-27
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 fancymouse 的回复:]

引用 5 楼 jeiwt 的回复:
这个能具体点吗?
怎么个状态dp?
谢谢~


引用 4 楼 fancymouse 的回复:
这个当n,m其中有一个比较小的时候可以状态压缩dp。否则的话就麻烦了。
压以后复杂度基本是2^(3m)*log(n)
把一列的状态压缩起来,2^m个状态。转移方程可以写成这2^m个状态的线性组合的形式,因此就是个2^m * 2^m的矩阵的乘法。程序算……
[/Quote]
ライラちゃん、Tiling正是乃的拿手好戏哈。呵呵呵⋯⋯
  • 打赏
  • 举报
回复
嗯……4×4例外。
  • 打赏
  • 举报
回复
先水一个,楼主的囧头像(^O^)

也可以说我是猜的,但也不是瞎猜:)
前提是瓷砖能恰好铺满地面,如果瓷砖是交错的,则至少有一边必须是奇数块砖,
而此题8×8不符合此条件。所以一组两块砖或者都横着铺或者都竖着铺。

另外,m×n有可能出现铺不满的情况。
xinzaiyiqi 2010-06-24
  • 打赏
  • 举报
回复
正在学习算法
jeiwt 2010-06-24
  • 打赏
  • 举报
回复
...
这个是编程之美的扩展问题
有题无解~

[Quote=引用 11 楼 jakiejiajia 的回复:]
编程之美上有原题
[/Quote]
jakiejiajia 2010-06-23
  • 打赏
  • 举报
回复
编程之美上有原题
绿色夹克衫 2010-06-22
  • 打赏
  • 举报
回复
又看到这个问题了,可以看看这个链接的内容

http://en.wikipedia.org/wiki/Domino_tiling
jeiwt 2010-06-22
  • 打赏
  • 举报
回复
有人说dp,有人说穷举(穷举如何判断是否现在这种铺法以前没出现过??不懂)

能给个代码么?或者伪代码也行,大概思路

谢谢

michael122 2010-06-22
  • 打赏
  • 举报
回复
m*n 的话,似乎只能穷举来做了
定义一个m×n的数组来记录当前状态,用回溯法搜吧
jeiwt 2010-06-22
  • 打赏
  • 举报
回复
这个能具体点吗?
怎么个状态dp?
谢谢~

[Quote=引用 4 楼 fancymouse 的回复:]
这个当n,m其中有一个比较小的时候可以状态压缩dp。否则的话就麻烦了。
压以后复杂度基本是2^(3m)*log(n)
[/Quote]
fanster28_ 2010-06-22
  • 打赏
  • 举报
回复
数学解必然抽象
jeiwt 2010-06-22
  • 打赏
  • 举报
回复
看了下,还是不大懂~~

[Quote=引用 8 楼 litaoye 的回复:]
又看到这个问题了,可以看看这个链接的内容

http://en.wikipedia.org/wiki/Domino_tiling
[/Quote]
FancyMouse 2010-06-22
  • 打赏
  • 举报
回复
这个当n,m其中有一个比较小的时候可以状态压缩dp。否则的话就麻烦了。
压以后复杂度基本是2^(3m)*log(n)
超级大笨狼 2010-06-21
  • 打赏
  • 举报
回复
我觉得可以先写个递归算法,从小到大实现,然后观察结果规律,找到递推式,然后再用数学归纳法去证明之。
jeiwt 2010-06-21
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 windsonzhl 的回复:]
地板面积64单位,瓷砖面积2单位,总共需要瓷砖32块。

每块瓷砖可以横放也可以竖放,但排列组合中的乘法原理肯定不对,因为瓷砖与瓷砖之间有制约。
应该是f(m) = 2的(m - 1)次方吧,也就是应用乘法原理所得结果除以2。
[/Quote]


这是猜的吧~~
  • 打赏
  • 举报
回复
地板面积64单位,瓷砖面积2单位,总共需要瓷砖32块。

每块瓷砖可以横放也可以竖放,但排列组合中的乘法原理肯定不对,因为瓷砖与瓷砖之间有制约。
应该是f(m) = 2的(m - 1)次方吧,也就是应用乘法原理所得结果除以2。

33,007

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧