编程之美4.2扩展问题

来源:互联网 发布:nba2k15mc季后赛数据 编辑:程序博客网 时间:2024/05/01 23:15

1, 用1*2的砖覆盖8*8的地板有多少种覆盖方式?如果是n*m的地砖呢?

 

首先,使用蛮力计算:

 

 

算法的复杂度为pow(2, 64)。

 

计算结果:

 

PlanNum: 12988816
time: 1891

 

考虑使用动态规划的方法。观察下面的图形:

 

- - - - - - - -

* * * * * * * *

* * * * * * * *

* * * * * * * *

* * * * * * * *

* * * * * * * *

* * * * * * * *

* * * * * * * *

 

如果第一行的地砖全部横放,问题简化为7*8的规模。在看下面两个图形:

- - - - - - - -

- - - - - - - -

* * * * * * * *

* * * * * * * *

* * * * * * * *

* * * * * * * *

* * * * * * * *

* * * * * * * *

 

| | | | | | | | 

| | | | | | | | 

* * * * * * * *

* * * * * * * *

* * * * * * * *

* * * * * * * *

* * * * * * * *

* * * * * * * *

 

这两个问题都可以复用问题6*8结果。当然不是所有的情况都可以简化。简化的条件在于已经铺满地砖的最后一行要求是行放,或者是竖着放的地砖的下半块。否则,必须继续向下面一行求解。代码如下:

 

 

计算结果:

 

PlanNum: 12988816
time: 3687

 

可以看到时间反而超过蛮力的方法。我想原因在于为了可以重用子问题的解所作的判断和维护工作消耗了更多的时间。我统计了一下各个子问题结果被复用的次数:

 

0: 186272
1: 35970
2: 4726
3: 1004
4: 120
5: 34
6: 1
7: 0

 

并不代表解法2就一无是处。事实上,可以想见对于大规模的问题,解法2一定能体现出比解法1的优势。比如我将问题改为10*8,解法1的结果为:

 

PlanNum: 1031151241
time: 155250

 

解法2的结果为:

 

PlanNum: 1031151241
time: 141266

 

可以看到解法2已经快了15秒左右,差不多快了10%。当然,这个解法2仍然不够好。原因在于可重用的粒度还比较粗。但是一时之间也没有想出更好的可行算法。有空再想。

 

问题2,用p*q的瓷砖能覆盖N*M的地板吗?

 

这完全是一道数学题。可以想见,如果N可以整除p,M可以整除q,或者两组数字的搭配对调一下,则p*q的地砖一定可以覆盖N*M的地板。不用任何证明。问题是,这是必要条件吗?不是,可以举出反例。

 

还有一个条件可以比较容易想到,必要条件之一为N*M可以整除p*q。问题是,这是充分条件吗?当然不是,反例很容易举出。

 

还是规矩一点,用数学式表示一下吧,如果N*M的地板能被p*q的瓷砖铺满,一定可以满足下面两个方程式:

 

M = x1p + y1q (x1和y1为任意非负整数解)

N = x2p + y2q (x2和y2为任意非负整数解)

 

暂时没有什么想法了,先放在这里吧。

原创粉丝点击