POJ1185 炮兵阵地(状态压缩dp)

https://ac.nowcoder.com/acm/problem/16886

  思路:m<=10,每行用0~1023数字的二进制数来表示状态,1表示能放,0表示不能放。同时他要满足不能放在途中H处,

那么把每行PHPH的字符串转换成0101串的状态,H记为1,p记为0,记录在statu。判断一个能不能根据这个状态放在地图上,

只要看他们&运算是不是0(不是0说明有棋子放在H上)。

  因为炮兵能攻击到他正下方的2行,所以用dp记录他当前行状态以及上一行状态。
  dp[i][j][k]表示在第i行中状态为j,第i-1行状态为k是的最大能放棋子数。
  在第i行中,用now表示当前行状态,p表示上一行状态,lp表示上上行状态,num[x]表示状态x的棋子数。
  dp方程:dp[i][now][p]=max(dp[i-1][p][lp]+num[now])   {lp取1~up},up表示合法状态上限。
  每次都用&运算判断该行与上一行,与上上行是否合法。
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<sstream>
#include<vector>
#include<stack>
#include<deque>
#include<cmath>
#include<map>
#include<queue>
#include<bitset>
//#include<hash_map>
#define sd(x) scanf("%d",&x)
#define lsd(x) scanf("%lld",&x)
#define ms(x,y) memset(x,y,sizeof x)
#define fu(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define all(a) a.begin(),a.end()
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
//using namespace __gnu_cxx;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int maxn=1e3+79;
const int mod=998244353;
const ll INF=0x7f7f7f7f;
const double pi=acos(-1);
ll dp[10][1030][1030];
//第i行,第i-1行状态,第i-2行状态
int num[1030],statu[1030],n,m;
bool check(int x,int statu)
{
    //按地图看该状态能不能放
    if((x&statu)!=0) return 0;
    //检查x状态是否合法
    if((x&(x>>1))!=0 || (x&(x>>2))!=0) return 0;
    return 1;
}
int main()
{
    sd(n);sd(m);
    fu(i,1,n)
    {
        //把PHPH的字符串转换成0101串的状态,H记为1,p记为0,记录在statu
        string s;cin>>s;
        int x=1;//记录处于第几位
        fd(j,s.size()-1,0)
        {
            if(s[j]=='H') statu[i]+=x;
            x<<=1;//x左移一位
        }
    }
    int up=(1<<m)-1;//合法状态上限
    fu(i,1,up)
    {
        num[i]=num[i>>1]+(i&1);//状态为i的棋子数
    }
    //特判n=1的情况
    if(n==1)
    {
        int ans=0;
        fu(i,0,up)
        {
            if(!check(i,statu[1])) continue;
            ans=max(ans,num[i]);
        }
        printf("%d\n",ans);
        return 0;
    }
    //初始化
    fu(now,0,up)
    {
        if(!check(now,statu[2])) continue;
        fu(p,0,up)
        {
            if(!check(p,statu[1])||(now&p)!=0) continue;
            dp[0][now][p]=num[now]+num[p];
        }
    }
    fu(i,3,n) 
    {
        fu(now,0,up)//当前状态 
        {
            if(!check(now,statu[i])) continue;
            fu(p,0,up)//上一行状态
            {
                if(!check(p,statu[i-1])||(now&p)!=0) continue;
                fu(lp,0,up)//上上行状态
                {
                    if(!check(lp,statu[i-2])||(p&lp)!=0||(now&lp)!=0) continue;
                    dp[i&1][now][p]=max(dp[i&1][now][p],dp[(i-1)&1][p][lp]+num[now]);
                }
            }
        }
    }
    ll ans=0;
    fu(now,0,up) fu(p,0,up)
    {
        if((now&p)==0)//判断是否合法
        ans=max(ans,dp[n&1][now][p]);
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted on 2020-08-15 13:18  Aminers  阅读(140)  评论(0)    收藏  举报

导航