poj1185 [NOI2001]炮兵阵地

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\n",ans);
    return 0;
}

 

posted @ 2017-12-23 10:15  zzzzx  阅读(256)  评论(2编辑  收藏  举报