標籤:dp
連結:http://poj.org/problem?id=1185
題意:一個地圖上有兩種地形,H和P,P上可以放一個炮,攻擊範圍是上下左右各兩格,問的是最多可以再地圖上放多少個炮。行N <= 100,列M <= 10。
思路:因為上下左右各兩格內不能放置炮,所以每一行的狀態數從2^10減少到60種。狀態轉移方程為:dp[i][j][k]=max(dp[i-1][k][l]+bb[j])。dp[i][j][k]表示在第i行狀態為j,在第i-1行狀態為k的前i行一共放置的炮塔數。bb[j]表示狀態k中整行的炮塔數。手敲這道題後對狀壓DP開始有所熟悉。
代碼:
#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<map>#include<cstdlib>#include<queue>#include<stack>#include<vector>#include<ctype.h>#include<algorithm>#include<string>#define PI acos(-1.0)#define maxn 10005#define INF 0x7ffffffftypedef long long ll;using namespace std;int judge(int x){ if((x&(x<<1))==0&&((x&(x<<2))==0)&&(((x<<1)&(x<<2))==0)) return 1; return 0;}int main(){ int row[105]={0}; int aa[105]={0}; int bb[105]={0}; int top=0; char land[105][15]; int dp[105][60][60]={0}; int r,c; scanf("%d%d",&r,&c); for(int i=0;i<(1<<c);i++) { if(judge(i)) { int k=i; while(k) { if(k%2==1) bb[top]++; k/=2; } aa[top++]=i; } } for(int i=0;i<r;i++) { scanf("%s",land[i]); for(int j=0;j<c;j++) { row[i]*=2; if(land[i][j]=='P') row[i]++; } } for(int i=0;i<top;i++) { if((aa[i]&row[0])==aa[i]) { dp[0][i][0]=bb[i]; } } for(int i=0;i<top;i++) { for(int j=0;j<top;j++) { if((aa[i]&aa[j])==0&&(aa[i]&row[1])==aa[i]&&(aa[j]&row[0])==aa[j]) dp[1][i][j]=dp[0][j][0]+bb[i]; } } for(int i=2;i<r;i++) { for(int j=0;j<top;j++) { for(int k=0;k<top;k++) { for(int l=0;l<top;l++) { if((aa[j]&aa[k])==0&&(aa[l]&aa[j])==0&&(aa[l]&aa[k])==0&&(aa[j]&row[i])==aa[j]&&(aa[k]&row[i-1])==aa[k]&&(aa[l]&row[i-2])==aa[l]) dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+bb[j]); } } } } int ans=0; for(int i=0;i<top;i++) { for(int j=0;j<top;j++) { if(dp[r-1][i][j]>ans) ans=dp[r-1][i][j]; } } printf("%d\n",ans);}
POJ 1185 炮兵布陣 狀壓DP