http://poj.org/problem?id=1185
三维装压dp,压缩上一行状态与本行状态,枚举上两行状态转移
第一维可以滚掉,实际复杂度只枚举符合情况的情况,每行状态不会超过60并非$2^M$,(然而luogu还是跑T了),证明参见组合数
#include<cstdio> #include<cstring> #include<algorithm> const int maxnm = 1001; const int maxn = 11; int n,m; char a[maxn]; int cant[maxn*10]; int map[101][11]; bool check(int x,int i) { if(x&cant[i])return false; if(x&(x<<1)||x&(x<<2))return false; return true; } int dp[2][1<<maxn][1<<maxn]; int num[1<<maxn]; int main( ) { scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) { scanf("%s",a) ; for(int j=0;j<m;++j) if(a[j]=='H') cant[i]|=(1<<j); } int po=(1<<m)-1; for(int k,i=1;i<=po;++i) { if(!check(i,0))continue; k=i;while(k) { num[i]+=(k&1); k>>=1; } } int ans=-1; for(int i=1;i<=n;++i) { for(int j=1;j<=po;++j) { if(!check(j,i))continue; for(int k=1;k<=po;++k) { if(!check(k,i-1)||(k&j)) continue; for(int p=1;p<=po;++p) { if(!check(p,i-2)||(p&j)||(k&p)) continue; dp[i&1][k][j]=std::max(dp[i&1][k][j],dp[(i&1)^1][p][k]+num[j]); } if(i==n)ans=std::max(ans,dp[n&1][k][j]); } } } printf("%d ",ans); return 0; }