炮兵阵地题解

炮兵阵地题解

状压DP的恶(mu)心(ban)题,

我们可以发现题目中:m<=10

无疑,肯定是这一维表状态,

题目中,若在一点布置炮兵,则左右四点不能布置(可以预处理粗来)

但问题是上下四点也不能布置,

所以在DP时我们需要枚举上上行,上一行,这一行的状态,

dp数组也要用两维表示这一行和上一行的状态,

但如果用三维数组则会爆空间,用循环数组省一省。

#include<bits/stdc++.h>
using namespace std;
const int N=106,M=1026; 
int n,m,o1=2,o2=0,o3=1,ans=-1,t,p,q,w,g[N],h[M],num[N],flag[N][M],dp[4][M][M];
char c[14];
inline int read(){
   int T=0,F=1; char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-') F=-1; ch=getchar();}
   while(ch>='0'&&ch<='9') T=(T<<3)+(T<<1)+(ch-48),ch=getchar();
   return F*T;
}
int main(){
    n=read(),m=read();
    for(int i=0;i<(1<<m);++i){
        p=i,q=0;
        while(p) q+=(p&1),p>>=1;
        h[i]=q;
    }//预处理出每一种状态有几个炮兵
    for(int i=1;i<=n;++i){
        scanf("%s",c);
        for(int j=0;j<m;++j) g[i]+=((c[m-j-1]=='P')<<j);
        //g[],求出平原上的所有可能状态
        for(int j=0;j<=g[i];++j)
            if(((j&g[i])==j)&&(!((j<<1)&j))&&(!((j<<2)&j))) flag[i][++num[i]]=j;
        //flag[i][]:第i行,满足不互相打到的所有状态
    } 
    memset(dp,-1,sizeof(dp));
    //dp[i][j][k]:第i行,这一行状态为j,上一行状态为k,第一位用循环数组省空间
    for(int i=1;i<=num[1];++i) dp[0][flag[1][i]][0]=h[flag[1][i]];
    for(int i=1;i<=num[1];++i){
        p=flag[1][i];
        for(int j=1;j<=num[2];++j){
            q=flag[2][j];
            if(p&q) continue;
            dp[1][q][p]=max(dp[1][q][p],dp[0][p][0]+h[q]);
        }
    }  
    //处理第一二行的dp初值(p&q代表同一列有炮兵)
    for(int i=3;i<=n;++i){
        t=o1,o1=o2,o2=o3,o3=t;
        for(int j=1;j<=num[i-2];++j){
            p=flag[i-2][j];
            for(int k=1;k<=num[i-1];++k){
                q=flag[i-1][k];
                for(int ww=1;ww<=num[i];++ww){
                    w=flag[i][ww];
                    if((p&q)||(p&w)||(q&w)) continue;//同一列有炮兵就跳过
                    dp[o3][w][q]=max(dp[o3][w][q],dp[o2][q][p]+h[w]);               
                }
            }
        }
    }
    for(int i=1;i<=num[n-1];++i){
        p=flag[n-1][i];
        for(int j=1;j<=num[n];++j){
            q=flag[n][j];
            if(p&q) continue;
            ans=max(ans,dp[o3][q][p]);
        }
    }  
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ljk123-de-bo-ke/p/11319344.html