链接: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 0x7fffffff typedef 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); }
时间: 2024-12-25 11:30:43