【洛谷P2704】炮兵阵地

题目大意:定义一个炮兵会影响该点所在坐标上下左右两个格子的范围,求一个 N*M 的网格里最多可以放多少个炮兵。

题解:发现这个问题有需要记录两个状态,即:上一层的状态和上两层的状态,若直接进行记录,空间可能会起飞。发现对于一个合法的状态来说,需要满足一行中相邻的两个 1 必须位距离大于等于 2,且满足山地位置不能放炮兵,仅考虑第一个约束条件,先打一个表发现,在 1024 个状态范围内仅有 60 个状态满足第一个条件,因此采用直接记录下满足约束 1 的状态,并通过记录每一行的山地平原情况进行位与即可得到合法状态。时间复杂度为 \(O(100*60*60*60)=O(Accepted)\)

代码如下

#include <bits/stdc++.h>
using namespace std;

char s[20];
int n,m,ans;
int G[101],f[101][61][61],valid[61],tot,num[61];

void read_and_parse(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        for(int j=1;j<=m;j++)if(s[j]=='H')G[i]|=1<<j-1;
    }
    for(int i=0;i<1<<m;i++)
        if(!(i&i<<1)&&!(i&i<<2)){
            valid[++tot]=i;
            int res=i;
            while(res)res-=res&-res,++num[tot];
        }
}

void solve(){
    for(int i=1;i<=tot;i++)
        for(int j=1;j<=tot;j++)
            if(!(valid[i]&valid[j])&&!(valid[i]&G[2])&&!(valid[j]&G[1]))
                f[2][i][j]=num[i]+num[j];
    for(int i=3;i<=n;i++)
        for(int j=1;j<=tot;j++)if(!(valid[j]&G[i]))
            for(int k=1;k<=tot;k++)
                if(!(valid[k]&G[i-1])&&!(valid[k]&valid[j]))
                    for(int w=1;w<=tot;w++)
                        if(!(valid[w]&G[i-2])&&!(valid[w]&valid[k])&&!(valid[w]&valid[j])){
                            f[i][j][k]=max(f[i][j][k],f[i-1][k][w]+num[j]);
                            ans=max(ans,f[i][j][k]);
                        }
    printf("%d\n",ans);
}

int main(){
    read_and_parse();
    solve();
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/wzj-xhjbk/p/10556430.html