題意:給出一個h*w的矩陣,用長為1寬為2,或者長為2,寬為1的骨牌來填滿,求方案數。
題解:放骨牌的時候要麼橫著放,要麼豎著放。現在來規定放置方式,對於矩陣上任意一個點[i,j],在上面放置一塊骨牌,如果橫著放,那麼佔據[i,j], [i,j+1];如果豎著放則佔據[i,j] ,[i-1,j],並且當第 i 行放置完成後第 i-1之前的所有位置行必須是被骨牌填滿的。
#include <algorithm>#include <iostream>using namespace std;#define bit(x) (1<<x)#define lint __int64int state, h, w;lint dp[12][1<<12];bool check ( int st ) /* 檢驗第一行的放置方案 */{for ( int i = 0; i < w; i++ ){if ( 0 == (st & bit(i)) ) /* 第i點為0,那麼留給它的下一行來覆蓋,因為豎著放是覆蓋點[i,j],[i-1,j],可行 */continue;if ( i == w - 1 ) /* 為1且已經是最右邊的點,不可能再橫著放下一塊骨牌了,不可行 */return false;if ( ! (st & bit(1+i)) ) /* 本身為1且下一個點為0,不滿足橫著放的條件,因為橫著放覆蓋點[i,j],[i,j+1],不可行*/return false;i++; /* 到這一步說明是點i橫著放下一塊骨牌,那麼點i,和點i+1都是1,直接跳到i+2(兩次i++) */}return true;}bool isLeagal ( int st1, int st2 ) /* 檢驗狀態轉移是否合法 */{for ( int i = 0; i < w; i++ ){if ( (st1 & bit(i)) != 0 ) {if ( (st2 & bit(i)) != 0 ){if ( i == w - 1 )return false;if ( 0 == (st2 & bit(i+1)) || 0 == (st1 & bit(i+1)) )return false;i++;}}else{if ( (st2 & bit(i)) == 0 ) return false;}}return true;}int main(){while ( scanf("%d %d", &h, &w) && (h+w) ){if ( (h * w) % 2 ){printf("0\n");continue;}if ( w > h ) swap(w,h);int i, j, k;state = (1 << w) - 1;memset(dp,0,sizeof(dp));for( i = 0; i <= state; i++ )if ( check(i) ) dp[h][i] = 1;for ( i = h-1; i >= 1; i-- ){for ( j = 0; j <= state; j++ ){for ( k = 0; k <= state; k++ )if ( isLeagal ( k, j ) )dp[i][j] += dp[i+1][k];}}printf("%I64d\n",dp[1][state]);}return 0;}