廣場鋪磚問題

題意: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 }
AC代碼
相關文章
相關標籤/搜索