【Luogu】P2704炮兵阵地(状压DP)

  题目链接

  话说还真没见过能影响两行的状压。想了半天想出来f数组再多一维就能表示,但是没想到怎么才能不爆空间……

  也是从这道题里学到的一个妙招。

  可以把合法状态存到一个数组里,然后用数组下标来映射状态。感觉好强啊

  然后……这题差不多就完了。

  

#include<cstdio>
#include<cctype>
#include<algorithm>
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

inline int getlen(int x){
    int ans=0;
    while(x){
        if(x&1)    ans++;
        x>>=1;
    }
    return ans;
}

int f[110][70][70];
int s[70],w[70],cnt;
int state[110];
int Ans;
int main(){
    int n=read(),m=read();
    int Max=(1<<m)-1;
    for(int i=1;i<=n;++i){
        char c[11];
        scanf("%s",c+1);
        for(int j=1;j<=m;++j){
            state[i]=state[i]<<1;
            if(c[j]=='H')    state[i]++;
        }
    }
    for(int i=0;i<=Max;++i){
        if(i&(i>>1)||i&(i>>2))    continue;
        s[++cnt]=i;
        w[cnt]=getlen(i);
        if(!(state[1]&i))    f[1][cnt][1]=w[cnt];
    }
    for(int i=1;i<=cnt;++i)
        for(int j=1;j<=cnt;++j){
            if(s[i]&s[j]||state[2]&s[i]||state[1]&s[j])    continue;
            f[2][i][j]=w[i]+w[j];
        }
    for(int i=3;i<=n;++i)
        for(int j=1;j<=cnt;++j){
            if(state[i]&s[j])    continue;
            for(int k=1;k<=cnt;++k){
                int ans=0;
                if((state[i-1]&s[k])||(s[j]&s[k]))    continue;
                for(int l=1;l<=cnt;++l){
                    if((state[i-2]&s[l])||(s[j]&s[l])||(s[k]&s[l]))    continue;
                    ans=std::max(ans,f[i-1][k][l]);
                }
                f[i][j][k]=ans+w[j];
            }
        }
    for(int i=1;i<=cnt;++i)
        for(int j=1;j<=cnt;++j)    Ans=std::max(Ans,f[n][i][j]);
    printf("%d",Ans);
    return 0;
}
原文地址:https://www.cnblogs.com/cellular-automaton/p/7613498.html