題意:
問一個 L*4 的矩形,用2*1的小矩形組成有多少種組法。
思路:
遞推。用一個4bit的整數表示“行狀態”。寫出15個遞推式即可。
首先,定義 f [ i ] [ j ] 爲, 已組成長度 (i - 1)* 4 的完美矩形, 第 i 行的狀態是 j (0~15)的方案數。那麼我們可以考察 f [ i ] [ j ] 可以怎麼求得。
注意下面的狀態方程的推導,圍繞的思路不僅是要填滿 15(1111) 這個“滿”狀態,而是要填滿所有1~15的狀態( i 行才能根據 i - 1 行轉移),所以2情況和5情況,不是重複的,動態規劃裏所有的一切都是圍繞“狀態”的概念來展開。
1. 【豎放】首先,如果在 i - 1 行有缺某些位,放上一塊(豎着放)之後, i-1行的該位被填上,而i行的該位會突出,狀態碼剛好是對15(1111)取補。例如
2. 【橫放】假設 i - 1 行已經完美覆蓋,那麼我們總可以在 i 行 橫放 1塊或2塊積木來得到新的狀態。例如
f [ i ][ 6 ] 、 f [ i ][ 12 ] 與 f [ i ][ 3 ] 情況類似,圖就不贅畫了。
3. 如果經過前述 i 行 有突出一個位的, 我們還可以通過橫放一個積木補上來將其填得更滿,例如:
注意是在同一行(i行)橫放積木,所以第一個下標全是 i , 其餘情況類似,不畫。
直到這裏,我們把 0 ~ 14 的狀態都填好了,接下來考慮最終極的, 15(1111,滿行)狀態的情況。
4. i - 1 行缺 連2位 的情況(0011 = 3, 1001 = 9, 1100 = 12),可以通過放置2個豎的積木和1個橫的積木達到完美,例如
其他2種情況不再贅畫。
5. i - 1 行如果已經是滿的,我們直接橫放2個積木,i 行也滿,這種不用畫了吧。
代碼:
// Problem#: 5855
// Submission#: 1456823
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <stdio.h>
#define maxx 10000
#define maxw 1000
int f[maxx+9][1<<4] ; //
int main () {
int L,n ;
f[1][0] = f[1][3] = f[1][6] = f[1][12] = f[1][15] = 1 ;
for ( int i = 2 ; i <= maxw ; ++i ) {
// 豎放 1
for ( int j = 0 ; j <= 15 ; ++j ) {
f[i][j] = f[i-1][15-j] ;
}
// 橫放 2
f[i][3] += f[i-1][15] ;
f[i][6] += f[i-1][15] ;
f[i][12] += f[i-1][15] ;
// 橫加豎 3
f[i][7] += f[i][4] + f[i][1] ;
f[i][14] += f[i][8] + f[i][2] ;
// 混合型 4 ( 2豎1橫 )
f[i][15] += f[i-1][3] + f[i-1][6] + f[i-1][12] ;
// 混合型 5 ( 2橫 )
f[i][15] += f[i-1][15] ;
}
scanf ( "%d" , &n ) ;
for ( int cas = 1 ; cas <= n ; ++cas ) {
scanf ( "%d" , &L ) ;
printf ( "%d %d\n" , cas , f[L][15] ) ;
}
}