【codevs1647】炮兵阵地

这个题是一个经典的状压dp,m<=10,意味着我们可以将每一层的状态压起来,提前预处理好,然后枚举当前在哪一层和i层 i-1层 i-2层的状态,理论上来说,这样最坏的时间复杂度是O(2^3m*n),但是因为障碍物的存在,以及预处理当中对左右格子的判断,时间复杂度会大大优于最坏情况,所以能够卡着过

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
using namespace std;
vector<int>mmp[110];
char s[15];
int di[110],n,m,dp[2][1030][1030],tail,ans;
inline void init()//预处理好所有能够成为状态的方案,按层存起来 
{
    for(int i=0;i<=(2<<(m-1))-1;i++)
    {
        if(!((i>>1)&i)&&!((i>>2)&i)&&!((i<<1)&i)&&!((i<<2)&i))//左右两格不能有棋子 
        {
            for(int j=1;j<=n;j++)
            {
                if(!(di[j]&i))//不能与地形有冲突 
                    mmp[j].push_back(i);
            }
        }
    }
}
inline int get(int x)//数数这个状态有多少棋子 
{
    int re=0;
    while(x)
    {
        if(x&1)
            re++;
        x>>=1;
    }
    return re;
}
int main()
{
    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')
                di[i]|=(1<<(m-j));
        }
    }
    init();
    for(int i=0;i<mmp[1].size();i++)//提前预处理好前两层状态,方便下面运算 
        for(int j=0;j<mmp[2].size();j++)
            if(!(mmp[1][i]&mmp[2][j]))
                dp[0][mmp[1][i]][mmp[2][j]]=max(dp[0][mmp[1][i]][mmp[2][j]],get(mmp[1][i])+get(mmp[2][j]));
    for(int i=3;i<=n;i++)//枚举现在到了第几层 
    {
        tail=1-tail;//滚动数组的小技巧 
        for(int j=0;j<mmp[i-2].size();j++)//枚举前两层状态 
            for(int k=0;k<mmp[i-1].size();k++)
            {
                if(!(mmp[i-2][j]&mmp[i-1][k]))//一个小优化 
                {
                    for(int l=0;l<mmp[i].size();l++)//枚举现在的状态 
                    {
                        if(!(mmp[i-2][j]&mmp[i][l])&&!(mmp[i-1][k]&mmp[i][l]))//三行的炮兵都不能攻击到对方 
                        {
                            dp[tail][mmp[i-1][k]][mmp[i][l]]=max(dp[tail][mmp[i-1][k]][mmp[i][l]],dp[1-tail][mmp[i-2][j]][mmp[i-1][k]]+get(mmp[i][l]));
                            ans=max(ans,dp[tail][mmp[i-1][k]][mmp[i][l]]);//dp[i][j][k]表示当前在第 i层,i-1层选的方案:j,i层选的k,第一维可以滚动掉 
                        }
                    }
                }
            }
    }
    printf("%d",ans);
}

 

posted @ 2017-10-30 07:06  那一抹落日的橙  阅读(183)  评论(0编辑  收藏  举报