• 【NOI2001】炮兵阵地


    题意

    给你一张有N*M的平原和山地的图,只能在平原上放置炮兵,炮兵的攻击范围如图所示,求最多能放多少个炮兵?

    数据规模:N <= 100;M <= 10。

    分析

    此题比起入门级的状压,难在了状态更多,影响的也不只一行了,而是两行。

    所以我们需要加维+减状态

    dp[i][j][k],扫到i行为止,当前行的状态为j,上一行的状态为k的方案最大值。

    如果再把山地的算进去,状态就太多了,需要预处理剪掉一些。

    而相应的,预处理也要预处理1,2两行,枚举第i行时也必须枚举i-1行,i-2行。

    减状态的方法:映射。用cnt表示可行状态编号,id[ ]数组对应了这个状态

    还需要预处理出每个状态可以放置多少炮兵,便于统计答案

    注意好好算一下数组开多大,一念之差很容易RE or MLE

    #include<bits/stdc++.h>
    using namespace std;
    #define N 110
    #define ll long long
    
    ll ans=0,dp[N][N][N],num[N];
    int n,m,mx,cnt;
    int e[N][N],ok[N],okk[N][N],id[N];
    int mp[N];
    string s;
    
    int main()
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            cin>>s;
            for(int j=1;j<=m;j++)
                if(s[j-1]=='P')e[i][j]=1;
        }
        mx=(1<<m)-1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                mp[i]=(mp[i]<<1)+e[i][j];
        
        for(int i=0;i<=mx;i++)
        {
            if( (((i<<1)&i)==0) & (((i<<2)&i)==0) )
            {
                id[++cnt]=i;
                ok[cnt]=1;
                int pos=i;
                while(pos)
                {
                    if(pos&1)num[cnt]++;
                    pos>>=1;
                }
            }
        }    
        
        for(int i=1;i<=cnt;i++)
            if(ok[i] & ((id[i]&mp[1])==id[i]))
            {
                okk[1][i]=1;
                dp[1][i][0]=num[i];
            }    
        
        for(int i=1;i<=cnt;i++)
        {
            if(ok[i] & ((id[i]&mp[2])==id[i]))
            {
                okk[2][i]=1;
                for(int j=1;j<=cnt;j++)
                {
                    if(!okk[1][j])continue;
                    if( (id[i]&id[j])==0 )
                        dp[2][i][j]=max(dp[2][i][j],dp[1][j][0]+num[i]);
                }
            }
        }    
        
        for(int i=3;i<=n;i++)
            for(int j=1;j<=cnt;j++)
            {
                if(ok[j] & ((id[j]&mp[i])==id[j]))
                {
                    okk[i][j]=1;
                    for(int k=1;k<=cnt;k++)
                    {
                        if(!okk[i-2][k])continue;
                        if( (id[k]&id[j]) )continue;
                        for(int t=1;t<=cnt;t++)
                        {
                            if(!okk[i-1][t])continue;
                            if(((id[k]&id[t])==0) & ((id[t]&id[j])==0))
                                dp[i][j][t]=max(dp[i][j][t],dp[i-1][t][k]+num[j]);
                        }
                    }
                }
            }
            
        for(int i=1;i<=cnt;i++)
            for(int j=1;j<=cnt;j++)
                ans=max(ans,dp[n][i][j]);    
        cout<<ans;
        return 0;    
            
    }
    “Make my parents proud,and impress the girl I like.”
  • 相关阅读:
    6 开发工具IDE-pycharm
    5 循环控制
    react native 遇到的坑
    代码缩略图插件
    JEECMS-自定义标签[list]
    Jeecms自定义标签用法[单个内容]
    ReactNative环境搭建
    修改浏览器accept使支持@ResponseBody
    [转]MyEclipse for Spring2014破解
    js正则验证手机号
  • 原文地址:https://www.cnblogs.com/NSD-email0820/p/9520556.html
Copyright © 2020-2023  润新知