將題目轉換題意, 有一個M列的牆, 我們需要 使用 1*2 的小矩形 砌成N層高, 有多少不同的方案數量.
因為只有1*2的磚頭, 且只有豎立或者橫着放.
那么我們規定 豎立放置的磚頭屬於 較高的一層, 且 當前點放置磚頭則為1,否則為0
那么我們可以得出結論:
對於 I 層 狀態 X , 若當前位置為0,則下層必定為1. 則意味着下層必定包含 t = (~X)& Mask
對於 I+1 層 狀態 Y, 除了包含 狀態 t 之外, 剩下標記為1的 必須兩兩成對.才可符合狀態.
注意 t = (~X)& Mask 這里要記得還要與 總集合MASK相與. 把狀態限定在MASK之內
解題代碼:
#include<stdio.h> #include<stdlib.h> #include<string.h> typedef long long LL; typedef unsigned int uint; const int N = 1<<11; /* 計算結果代碼部分 LL ans[12][12]; LL dp[12][N+10]; int n, m; bool check( uint x ){ for(uint i = 0; i < m; i++) { if( x&(1<<i) ) { if( i+1 >= m ) return false; if( ( x&(1<<(i+1) ) ) == 0 ) return false; i++; } } return true; } int main() { freopen("6.out","w",stdout); memset( ans, 0, sizeof(ans) ); for(n = 1; n <= 11; n++) for(m = 1; m <= 11; m++) { memset( dp, 0, sizeof(dp) ); int Max = (1<<m)-1; for(int mask = 0; mask <= Max; mask++) if( check(mask) ) dp[0][mask] = 1; // for(uint i = 0; i < Max; i++) // if( dp[0][i] ) printf("%d ", i); puts(""); for(int h = 0; h < n-1; h++) { for(uint mask = 0; mask <= Max; mask++) { if( dp[h][mask] ){ uint t = (~mask)&Max; for(uint x = 0; x <= Max; x++) { // printf("mask = %u, t = %u, x = %u\n", mask, t, x ); if( ((x&t)==t) && check( t^x ) ) dp[h+1][x] += dp[h][mask]; } } } // cur = !cur; } // printf( (n==1&&m==1) ? "%lld" : ",%lld", dp[n-1][Max] ); ans[n][m] = dp[n-1][Max]; } printf("{\n"); for(int i = 0; i <= 11; i++) { printf("{"); for(int j = 0; j <= 11; j++) { printf( j == 0 ? "%lld" : ",%lld", ans[i][j] ); } printf( i == 11 ? "}\n" : "},\n"); } printf("};\n"); return 0; } */ LL ans[12][12] = { {0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,1,0,1,0,1,0,1,0,1,0}, {0,1,2,3,5,8,13,21,34,55,89,144}, {0,0,3,0,11,0,41,0,153,0,571,0}, {0,1,5,11,36,95,281,781,2245,6336,18061,51205}, {0,0,8,0,95,0,1183,0,14824,0,185921,0}, {0,1,13,41,281,1183,6728,31529,167089,817991,4213133,21001799}, {0,0,21,0,781,0,31529,0,1292697,0,53175517,0}, {0,1,34,153,2245,14824,167089,1292697,12988816,108435745,1031151241,8940739824}, {0,0,55,0,6336,0,817991,0,108435745,0,14479521761,0}, {0,1,89,571,18061,185921,4213133,53175517,1031151241,14479521761,258584046368,3852472573499}, {0,0,144,0,51205,0,21001799,0,8940739824,0,3852472573499,0} }; int main() { int n, m; while( scanf("%d%d",&n,&m) != EOF) { if(n+m == 0 ) break; printf("%lld\n", ans[n][m]); } return 0; }
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。