POJ 2663 完美覆蓋問題

2021-09-14 01:58:03 字數 1595 閱讀 7077

此題是北大演算法課的遞迴作業。想了半天也找不出遞推公式。網上的文章都是直接給出結論,而沒有推導過程,無異於耍流氓。

繼續尋找,直到看到此文才終於明白。

首先,列數n肯定要是偶數,因為n*3/2得是整數。

然後我們來想遞推公式。因為n是偶數,所以n-1, n-3這種奇數列,必然無法完全覆蓋。我們不考慮。

首先,f(n)可以由f(n-2)推得,則剩下的兩列還有三種方法。

所以f(n)至少要等於3 * f(n-2).

那麼f(n)可不可以由f(n-4)推得呢?對於剩下的4列,如果是上圖中任兩種情況的組合,那它實際上就還是f(n-2)中的情況,因此重合了。必須要找到一種無法被拆成完美2列的4列圖形。也就是說,單看兩列時是參差不齊的。這時才不與f(n-2)的情形重合。

那麼有沒有這種圖形呢?見下圖:

同理,6列的類似圖形是這樣:

可以看出這種圖形的特點:為了避免能被拆成2列的圖形,在內部要有參差不齊。方法就是一行平躺,然後其餘兩行兩邊豎著放,中間橫著放。嘗試幾次後就會發現只有這種方案。

因為平躺的那行可以在上面也可以在下面,因此無法分割的4列、6列、8列……的排列方法都是有兩種。
由此,我們便能寫出遞推公式:

f(2) = 3,

f(4) = 3 * f(2) + 2 * 1,

f(6) = 3 * f(4) + 2 * (f(2) + 1), // 後半部分是不可拆分4列和不可拆分6列的形狀數量。

f(n) = 3 * f(n-2) + 2 * (f(n-4) + f(n-6) + ... + f(2) + 1)

= f(n-2) + 2 * (f(n-2) + f(n-4) + ... + f(2) + 1)

#includeusing namespace std;

// 遞迴計算

int calc(int n)

return sum;

}int main()

return 0;

}

上面程式已經能通過。但遞迴寫法會造成重複計算。可以用乙個陣列儲存計算結果。

另外既然答案要求f(0) = 1,則可以將遞推公式寫成:

f(n) = 3 * f(n-2) + 2 * (f(n-4) + f(n-6) + ... + f(0))
將f(n)與f(n-2)相減可得

f(n) = 4 * f(n-2) - f(n-4)
這下就簡單多了。

可以用迭代算出:

int f[30],n;

void init()

POJ2663 完美覆蓋

描述 一張普通的西洋棋棋盤,它被分成 8 乘 8 8 行 8 列 的 64 個方格。設有形狀一樣的多公尺諾牌,每張牌恰好覆蓋棋盤上相鄰的兩個方格,即一張多公尺諾牌是一張 1 行 2 列或者 2 行 1 列的牌。那麼,是否能夠把 32 張多公尺諾牌擺放到棋盤上,使得任何兩張多公尺諾牌均不重疊,每張多公...

POJ 2663 Tri Tiling 完美覆蓋

一張普通的西洋棋棋盤,它被分成 8 乘 8 8 行 8 列 的 64 個方格。設有形狀一樣的多公尺諾牌,每張牌恰好覆蓋棋盤上相鄰的兩個方格,即一張多公尺諾牌是一張 1 行 2 列或者 2 行 1 列的牌。那麼,是否能夠把 32 張多公尺諾牌擺放到棋盤上,使得任何兩張多公尺諾牌均不重疊,每張多公尺諾牌...

POJ 第三週 程式設計題 1 完美覆蓋

自己做完之後對比了下網上的解題思路都是歸納出遞迴式直接求值,這裡給出我的乙個搜尋方法。思路 include include using namespace std const int row 3 struct point point nextpoint char a,int x,int y,int ...