題意:ide
給你n * m的棋盤,問用1 * 2的棋子所有鋪滿的方案數。n,m <= 11spa
解:code
裸的狀壓DP。blog
咱們就設f[i][j]表示第i行狀態是j,前面i - 1行所有放滿的方案數。io
轉移的時候枚舉i - 1行的狀態,而後仍是DFS轉移。event
DFS的時候,若是i - 1行爲空,那這裏必須豎着放。class
不然若是前一格爲空的話,能夠橫着放。不然只能不放。基礎
而後把這一行搜到最後的時候更新一下。cli
預處理是直接搞出第一行的全部可行狀態。(update:只要設f[0][lm - 1] = 1便可)sed
算是比較基礎的吧。
1 #include <cstdio> 2 3 typedef long long LL; 4 const int N = 12; 5 6 LL f[N][1 << N]; 7 int n, m; 8 9 inline bool check(int s) { 10 bool f = 0; 11 for(int i = 0; i < m; i++) { 12 if((s >> i) & 1) { 13 f ^= 1; 14 } 15 else { 16 if(f) { 17 return 0; 18 } 19 } 20 } 21 return !f; 22 } 23 24 LL ans; 25 int state; 26 void DFS(int x, int y, int ns) { 27 if(y == m) { 28 f[x][ns] += ans; 29 return; 30 } 31 if(y > m) { 32 return; 33 } 34 if(!((state >> y) & 1)) { 35 DFS(x, y + 1, ns | (1 << y)); 36 return; 37 } 38 DFS(x, y + 1, ns); 39 if(y && (!((ns >> (y - 1)) & 1))) { 40 DFS(x, y + 1, ns | (1 << y) | (1 << (y - 1))); 41 } 42 return; 43 } 44 45 int main() { 46 scanf("%d%d", &n, &m); 47 48 int lm = 1 << m; 49 50 for(int i = 0; i < lm; i++) { 51 f[1][i] = check(i); 52 } 53 54 for(int i = 2; i <= n; i++) { 55 for(int j = 0; j < lm; j++) { // state of i - 1 56 //printf("f[%d][%d] = %lld \n", i - 1, j, f[i - 1][j]); 57 ans = f[i - 1][j]; 58 state = j; 59 DFS(i, 0, 0); 60 } 61 } 62 printf("%lld", f[n][lm - 1]); 63 return 0; 64 }