RQNOJ 328 炮兵陣地:狀壓dp
題目鏈接: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