【題意】:司令部的將軍們打算在N*M的網(wǎng)格地圖上部署他們的炮兵部隊。一個N*M的地圖由N行M列組成,地圖的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下圖。在每一格平原地形上最多可以布置一支炮兵部隊(山地上不能夠部署炮兵部隊);一支炮兵部隊在地圖上的攻擊范圍如圖中黑色區(qū)域所示: 

如果在地圖中的灰色所標(biāo)識的平原上部署一支炮兵部隊,則圖中的黑色的網(wǎng)格表示它能夠攻擊到的區(qū)域:沿橫向左右各兩格,沿縱向上下各兩格。圖上其它白色網(wǎng)格均攻擊不到。從圖上可見炮兵的攻擊范圍不受地形的影響。 
現(xiàn)在,將軍們規(guī)劃如何部署炮兵部隊,在防止誤傷的前提下(保證任何兩支炮兵部隊之間不能互相攻擊,即任何一支炮兵部隊都不在其他支炮兵部隊的攻擊范圍內(nèi)),在整個地圖區(qū)域內(nèi)最多能夠擺放多少我軍的炮兵部隊。  

【題解】:經(jīng)典的狀態(tài)壓縮dp。
              因為每行最多只有10個格子,考慮使用狀態(tài)壓縮。
              無效的狀態(tài)有很多,需要先預(yù)處理出所有合法狀態(tài),最多只有60種,存放在st[]。
              設(shè)dp[i][j][k]表示當(dāng)前第i行的狀態(tài)為st[j]且第i-1行的狀態(tài)為st[k]能夠擺放部隊的最大值。

              轉(zhuǎn)移方程:
                     dp[i][j][k] = max(cnt[j] + dp[i-1][k][kk])

              最后的ans = max(dp[n-1][i][j]).

【代碼】:
  1 #include "iostream"
  2 #include "cstdio"
  3 #include "cstring"
  4 #include "algorithm"
  5 #include "vector"
  6 #include "queue"
  7 #include "cmath"
  8 #include "string"
  9 #include "cctype"
 10 #include "map"
 11 #include "iomanip"
 12 #include "set"
 13 #include "utility"
 14 using namespace std;
 15 typedef pair<intint> pii;
 16 #define pb push_back
 17 #define mp make_pair
 18 #define fi first
 19 #define se second
 20 #define sof(x) sizeof(x)
 21 #define lc(x) (x << 1)
 22 #define rc(x) (x << 1 | 1)
 23 #define lowbit(x) (x & (-x))
 24 #define ll long long
 25 const int inf = 1 << 25;
 26 int n, m;
 27 char maz[110][15];
 28 int row[110];
 29 int dp[110][70][70];
 30 int st[70], tot, cnt[70];
 31 
 32 void init() {
 33     tot = 0;
 34     memset(cnt, 0, sof(cnt));
 35     int nn = 1 << m;
 36     for(int i = 0; i < nn; i++) {
 37         bool flag = true;
 38         int tmp = 0;
 39         for(int j = m - 1; j >= 0; j--) {
 40             if(i & (1 << j)) {
 41                 tmp++;
 42                 if((j >= 1) && (i & (1 << (j-1)))) {
 43                     flag = false;
 44                     break;
 45                 }
 46                 if((j >= 2) && (i & (1 << (j-2)))) {
 47                     flag = false;
 48                     break;
 49                 }
 50             }
 51         }
 52         if(flag) {
 53             st[tot] = i, cnt[tot++] = tmp;
 54         }
 55     } 
 56 }
 57 
 58 void solve() {
 59     init();
 60     for(int i = 0; i < n; i++)
 61         for(int j = 0; j < tot; j++)
 62             for(int k = 0; k < tot; k++)
 63                 dp[i][j][k] = -inf;
 64 
 65     for(int i = 0; i < tot; i++) {
 66         if(!(st[i] & row[0])) dp[0][i][0] = cnt[i];
 67         else dp[0][i][0] = -inf;
 68         for(int j = 1; j < tot; j++) dp[0][i][j] = -inf;
 69     }
 70 
 71     for(int i = 1; i < n; i++)
 72         for(int j = 0; j < tot; j++)
 73             if(!(row[i] & st[j])) 
 74                 for(int k = 0; k < tot; k++)
 75                     if(!(st[j] & st[k]))
 76                         for(int kk = 0; kk < tot; kk++)
 77                             if(!(st[j] & st[kk]))
 78                                 dp[i][j][k] = max(dp[i][j][k], cnt[j] + dp[i-1][k][kk]);
 79 
 80     int ans = 0;
 81     for(int i = 0; i < tot; i++)
 82         for(int j = 0; j < tot; j++)
 83             ans = max(ans, dp[n-1][i][j]);
 84     printf("%d\n", ans);
 85 }
 86 
 87 int main() {
 88     while(~scanf("%d%d", &n, &m)) {
 89         memset(row, 0, sof(row));
 90         for(int i = 0; i < n; i++) {
 91             scanf("%s", maz[i]);
 92             for(int j = m - 1; j >= 0; j--) {
 93                 row[i] <<= 1;
 94                 if(maz[i][j] == 'H') row[i] |= 1;
 95             }
 96         }
 97         solve();
 98     }
 99     return 0;
100 }
101