poj1185:炮兵阵地(状压dp)
也算是比较基础的状压dp了,跟做过的第二道比较又稍微复杂了一点
需要记录之前两行的状态。。
统计结果也稍有不同
另外还学习了一个得到一个整数二进制位 1 的个数的位运算方法
详见代码:
#include <iostream> #include <stdio.h> #include<string.h> #include<algorithm> #include<string> #include<ctype.h> using namespace std; #define MAXN 10000 int s[70]; int num[70]; int cant[110]; int dp[110][70][70]; int ns; int n,m; int ct(int x) { int res=0; while(x) { res++; x&=(x-1); } return res; } void setstate() { memset(num,0,sizeof(num)); for(int i=0;i<1<<10;i++) { if((i&(i<<1))==0&&((i&(i<<2))==0)) { s[ns]=i; num[ns++]=ct(i); } } } void ini() { memset(cant,0,sizeof(cant)); char s[20]; for(int i=1;i<=n;i++) { scanf("%s",s); for(int j=0;j<m;j++) { if(s[j]=='H') { cant[i]|=(1<<j); } } } } void solve() { memset(dp,0,sizeof(dp)); for(int i=0;i<ns&&s[i]<(1<<m);i++) { if((s[i]&cant[1])==0) dp[1][0][i]=num[i]; } for(int i=2;i<=n;i++) { for(int t=0;t<ns&&s[t]<(1<<m);t++) { if(s[t]&cant[i]) continue; for(int j=0;j<ns&&s[j]<(1<<m);j++) { if(s[j]&cant[i-2]) continue; for(int k=0;k<ns&&s[j]<(1<<m);k++) { if(s[k]&cant[i-1]) continue; if(s[j]&s[k]) continue; if(s[t]&cant[i]) continue; if((s[t]&s[j])||(s[t]&s[k])) continue; dp[i][k][t]=max(dp[i][k][t],dp[i-1][j][k]+num[t]); } } } } int ans=0; for(int i=1;i<=n;i++) { for(int j=0;j<ns&&s[j]<(1<<m);j++) { for(int k=0;k<ns&&s[k]<(1<<m);k++) ans=max(ans,dp[i][j][k]); } } printf("%d\n",ans); } int main() { ns=0; setstate(); while(scanf("%d%d",&n,&m)!=EOF) { ini(); solve(); } return 0; }