1. 程式人生 > >RQNOJ 328 炮兵陣地:狀壓dp

RQNOJ 328 炮兵陣地:狀壓dp

不用 壓縮 put iostream ++ express lan ott str

題目鏈接:https://www.rqnoj.cn/problem/328

題意:

  司令部的將軍們打算在N*M的網格地圖上部署他們的炮兵部隊。

  一個N*M的地圖由N行M列組成(N≤100,M≤10),地圖的每一格可能是山地(用‘H‘ 表示),也可能是平原(用‘P‘表示),如下圖。

  在每一格平原地形上最多可以布置一支炮兵部隊(山地上不能夠部署炮兵部隊);

  一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示:

    技術分享

  如果在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中的黑色的網格表示它能夠攻擊到的區域:沿橫向左右各兩格,沿縱向上下各兩格。

  圖上其它白色網格均攻擊不到。從圖上可見炮兵的攻擊範圍不受地形的影響。

  現在,將軍們規劃如何部署炮兵部隊,在防止誤傷的前提下(保證任何兩支炮兵部隊之間不能互相攻擊,即任何一支炮兵部隊都不在其他支炮兵部隊的攻擊範圍內)。

  問在整個地圖區域內最多能夠擺放多少我軍的炮兵部隊。

題解:

  表示狀態:

    m<=10,所以對每一行進行壓縮。

    dp[i][state1][state2] = max num of cannons(炮兵數量)

    i:該擺第i行

    state1:上上一行的狀態(i-2)

    state2:上一行的狀態(i-1)

  找出答案:

    max dp[n][state1][state2]

    枚舉state1,state2.

  如何轉移:

    now: dp[i][state1][state2]

    枚舉第i行填的方案為nex。

    如果nex符合第i行的地形,並且與state1,state2均沒有交集,則:

    dp[i+1][state2][nex] = max dp[i][state1][state2] + sum[nex]

    (sum[nex]為方案nex中的炮兵個數。)

  邊界條件:

    dp[0][0][0] = 0

    others = -1

    (第0行的上兩行方案均設為0,因為不填適用於任何地形)

  優化:

    (1)預處理field數組。

      field[i]為第i行的地形。每一位上1位山地,0為平原。

      判斷nex是否適用於第i行時,只需判斷是否有 state & field == 0

    (2)預處理在一行上的合法方案。

      在每一行上,兩個炮兵之間最少相距2格。利用此性質dfs然後存起來就好。

    (3)dp數組的下標state不再直接表示01狀態,而是換成s代表當前方案在dfs數組中的索引。

      省空間啊。。。

    (4)預處理出每一種行上合法方案的sum值,存起來。

      預處理時,最好用lowbit直接找出1,而不用逐位枚舉。

AC Code:

  1 // optimizations:
  2 // scheme: put == 1, blank == 0
  3 // field: mountain == 1, plain == 0
  4 // legal: scheme & field == 0
  5 // preprocess: legal scheme for rows
  6 //
  7 // state expression:
  8 // dp[i][state1][state2] = max num of cannons
  9 // i: considering ith row
 10 // state1: top row
 11 // state2: bottom row
 12 //
 13 // find the answer:
 14 // max dp[n][state1][state2]
 15 //
 16 // transferring:
 17 // now: dp[i][state1][state2]
 18 // if nex & field[i] == 0
 19 // dp[i+1][state2][nex] = max dp[i][state1][state2] + sum[nex]
 20 //
 21 // boundary:
 22 // dp[0][0][0] = 0
 23 // others = -1
 24 #include <iostream>
 25 #include <stdio.h>
 26 #include <string.h>
 27 #include <stack>
 28 #define MAX_N 105
 29 #define MAX_M 15
 30 #define MAX_S 65
 31 
 32 using namespace std;
 33 
 34 int n,m;
 35 int cnt;
 36 int ans;
 37 int sum[MAX_S];
 38 int field[MAX_N];
 39 int legal_state[MAX_S];
 40 int dp[MAX_N][MAX_S][MAX_S];
 41 
 42 void dfs(int col,int state)
 43 {
 44     if(col>=m)
 45     {
 46         legal_state[cnt++]=state;
 47         return;
 48     }
 49     dfs(col+1,state);
 50     dfs(col+3,state|(1<<col));
 51 }
 52 
 53 int cal_sum(int state)
 54 {
 55     int lowbit=state&-state;
 56     int cnt=0;
 57     while(lowbit)
 58     {
 59         cnt++;
 60         state^=lowbit;
 61         lowbit=state&-state;
 62     }
 63     return cnt;
 64 }
 65 
 66 void read()
 67 {
 68     memset(field,0,sizeof(field));
 69     cin>>n>>m;
 70     char c;
 71     for(int i=0;i<n;i++)
 72     {
 73         for(int j=0;j<m;j++)
 74         {
 75             cin>>c;
 76             field[i]<<=1;
 77             if(c==H) field[i]|=1;
 78         }
 79     }
 80 }
 81 
 82 void solve()
 83 {
 84     cnt=0;
 85     dfs(0,0);
 86     for(int i=0;i<cnt;i++)
 87     {
 88         sum[i]=cal_sum(legal_state[i]);
 89     }
 90     memset(dp,-1,sizeof(dp));
 91     dp[0][0][0]=0;
 92     for(int i=0;i<n;i++)
 93     {
 94         for(int s1=0;s1<cnt;s1++)
 95         {
 96             for(int s2=0;s2<cnt;s2++)
 97             {
 98                 int state1=legal_state[s1];
 99                 int state2=legal_state[s2];
100                 if(dp[i][s1][s2]!=-1 && !(state1&state2))
101                 {
102                     for(int s3=0;s3<cnt;s3++)
103                     {
104                         int nex=legal_state[s3];
105                         if(!(nex&field[i]) && !(nex&state1) && !(nex&state2))
106                         {
107                             dp[i+1][s2][s3]=max(dp[i+1][s2][s3],dp[i][s1][s2]+sum[s3]);
108                         }
109                     }
110                 }
111             }
112         }
113     }
114     ans=0;
115     for(int s1=0;s1<cnt;s1++)
116     {
117         for(int s2=0;s2<cnt;s2++)
118         {
119             ans=max(ans,dp[n][s1][s2]);
120         }
121     }
122 }
123 
124 void print()
125 {
126     cout<<ans<<endl;
127 }
128 
129 int main()
130 {
131     read();
132     solve();
133     print();
134 }

RQNOJ 328 炮兵陣地:狀壓dp