1. 程式人生 > >刷題11 矩形覆蓋問題

刷題11 矩形覆蓋問題

ret 操作 mage n-2 分享 rect round com ima

描述: 我們可以用2*1的小矩形橫著或者豎著去覆蓋更大的矩形。請問用n個2*1的小矩形無重疊地覆蓋一個2*n的大矩形,總共有多少種方法?

思路: 這種題開始肯定要找規律, 看了看, n = 1時, 一種方法; n = 2時, 兩種方法; n = 3時,三種方法; n = 4時, 五種方法; ... ; 很自然想起了斐波那契數列。

證明一下:

設 n 列一共有 f(n) 種無重疊的覆蓋方法,先上一個自己畫的圖方便理解。

技術分享圖片

1、對於n > 2的情況:首先我們可以知道小矩形是2 * 1,整個矩形為2 * n,所以我們在填充的時候只有橫著填充跟豎著填充。 所以思路就是將從第1列填充到第n列的情況分解.

怎麽分解呢,然後我又畫了下面這個圖, 方便理解。

技術分享圖片

我想求從A到G總共多少中走法,咋求呢? 我先分解, 在第一步我有兩種走法, 要麽走B要麽走C,然後B往後又有兩種走法,C往後又有...

所以,說這麽多,對於矩形填充所有情況, 那麽先走第一步, 兩種情況:豎著放或者橫著放。

(1)對於第一步豎著放: 直接占據一豎列就OK了, 然後還剩下 n-1 列, 而n-1 列有 f(n-1) 種填充方法, 所以第一步豎著放總共有 1 * f(n-1) = f(n-1) 種方法;

(2)對於第一步橫著放: 先放一個 2 * 1 小矩形,讓它占據第一行第一、二列, 此時還剩下 n-2 列加上一個第二行第一、二列的區域。 我們難以用科學的方法表示出來, 怎麽辦?那就繼續分解。

對於第二行第一、二列的區域,我們只存在唯一方式就是橫著放上小矩形, 這樣操作之後還剩下 n-2 列有 f(n-2) 種填充方法, 所以第一步橫著放總共有 1 * 1 * f(n-2) = f(n-2) 種方法。

那麽好了, 將這兩個合並就是n列一共的方法數了, 即 f(n-1) + f(n-2) = f(n) 。看到這個式子是不是很熟, 對, 斐波那契數列。

2、那好,現在考慮到 n = 2 的情況, 不用 f(n-1) + f(n-2) = f(n) 這個公式, 更不要直接窮舉, 用1中的思想考慮,可以得到: f(2) = 1 + 1 * 1 = 2 。

那現在可以寫代碼了:

 1
class Solution { 2 public: 3 int rectCover(int number) { 4 if(number < 3) 5 return number; 6 int first = 1; 7 int second = 2; 8 for(int i = 3; i <= number; i++) 9 { 10 second = first + second; 11 first = second - first; 12 } 13 return second; 14 } 15 };

順便想一下, 假如用 3 * 1 的小矩形填充 3 * n 的大矩形呢?

我們還是用 f(n) 表示 n 列的所有方法,第一步還是分兩種情況:

(1)橫著放: 橫著放占了三列, 剩下 n-3 列, 總共情況為 1 * 1 * f(n-3) = f(n-3)

(2)豎著放: 豎著放了一列, 剩下 n-1 列, 總共情況為 1 * f(n-1) = f(n-1)

所以 f(n) = f(n-1) + f(n-3)

接下來還有其他變形都OK了。

刷題11 矩形覆蓋問題