POJ 1185 炮兵陣地 狀壓dp
阿新 • • 發佈:2020-09-12
題意:
司令部的將軍們打算在N*M的網格地圖上部署他們的炮兵部隊。一個N*M的地圖由N行M列組成,地圖的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下圖。在每一格平原地形上最多可以佈置一支炮兵部隊(山地上不能夠部署炮兵部隊);一支炮兵部隊在地圖上的攻擊範圍如圖中黑色區域所示:如果在地圖中的灰色所標識的平原上部署一支炮兵部隊,則圖中的黑色的網格表示它能夠攻擊到的區域:沿橫向左右各兩格,沿縱向上下各兩格。圖上其它白色網格均攻擊不到。從圖上可見炮兵的攻擊範圍不受地形的影響。
現在,將軍們規劃如何部署炮兵部隊,在防止誤傷的前提下(保證任何兩支炮兵部隊之間不能互相攻擊,即任何一支炮兵部隊都不在其他支炮兵部隊的攻擊範圍內),在整個地圖區域內最多能夠擺放多少我軍的炮兵部隊。
Input
接下來的N行,每一行含有連續的M個字元('P'或者'H'),中間沒有空格。按順序表示地圖中每一行的資料。N <= 100;M <= 10。
Output
僅一行,包含一個整數K,表示最多能擺放的炮兵部隊的數量。Sample Input
5 4 PHPP PPHH PPPP PHPP PHHP
Sample Output
6
題解:
看一下M的資料範圍只有10,狀壓dp都可以狀壓20位+
然後因為一個位置駐紮的有炮兵,會影響下面兩行,所以我們的dp陣列既要儲存這一行的狀態又要儲存上一行的狀態
因為如果這樣的話,你在dp狀態轉移的時候就可以得到本行上面兩行的狀態
如果一個位置有炮兵,我們就給這個位置用二進位制1來表示,那麼會得到一個M長度的01串,這個串可以變成一個十進位制整數
例如:1001=9、11=3
這就是狀態壓縮,一般見到的都是二進位制狀態壓縮
dp方程:dp[i][j][k]表示第i行的狀態為j,第i-1行狀態為k
狀態轉移方程:dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+num_1[j]);
num_1[j]:第j個狀態中二進位制形勢下1的數量
l:l就是在列舉第i-2行的狀態是什麼
dp過程中把互斥的狀態去掉,例如狀態0110010 和狀態 0000010
這兩個狀態不可以同時出現在i、j、k、l狀態中,因為它們兩個有一個炮兵在同一個位置,而且它們豎向距離小於2,這樣就會攻擊到對方
可以使用&(與,只有1&1才等於1,其他都是0)操作來判斷
另外還需要注意某些位置有山,有山的位置不能放炮兵,也可以壓縮狀態之後使用&操作來判斷
程式碼:
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> using namespace std; typedef long long ll; const int maxn=100+10; const int N=1<<10; const int INF=1e9; int state[N],base[maxn],dp[maxn][N][N],num_1[N]; int main() { int n,m,num=0; char s[maxn][maxn]; scanf("%d%d",&n,&m); for(int i=0;i<n;++i) { scanf("%s",s[i]); for(int j=0;j<m;++j) { if(s[i][j]=='H') base[i]+=(1<<j); } } for(int i=0;i<(1<<m);++i) { if((i&(i<<1) || (i&(i<<2)))) continue; state[num]=i; int k=i; while(k) { if(k&1) num_1[num]++; k>>=1; } num++; } for(int i=0;i<num;++i) { if(state[i]&base[0]) continue; dp[0][i][0]=num_1[i]; } for(int i=1;i<n;++i) { for(int j=0;j<num;++j) { if(state[j]&base[i]) continue; for(int k=0;k<num;++k) { if(state[k]&base[i-1]) continue; if(state[k]&state[j]) continue; for(int l=0;l<num;++l) { if(i-2>=0 && state[l]&base[i-2]) continue; if(state[j]&state[l]) continue; if(state[k]&state[l]) continue; dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+num_1[j]); } } } } int maxx=0; for(int i=0;i<num;++i) { for(int j=0;j<num;++j) { maxx=max(maxx,dp[n-1][i][j]); } } printf("%d\n",maxx); return 0; }