题意: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 }