zoukankan      html  css  js  c++  java
  • P2704 [NOI2001]炮兵阵地

    依旧是状态压缩DP(什么叫依旧是,这不是第一道吗

    题目大意

    有N*M个方格,每个方格是平原(“P”)或者山地(“H”),如果是平原则可以布置炮兵

    每个炮兵的攻击范围是向上向下两格,向左向右两格,以及自己共5格,在攻击范围内不能再布置炮兵,问最多布置多少炮兵

    输入输出格式

    输入格式:

    第一行包含两个由空格分割开的正整数,分别表示N和M;

    接下来的N行,每一行含有连续的M个字符(‘P’或者‘H’),中间没有空格。按顺序表示地图中每一行的数据。N≤100;M≤10。

    输出格式:

    仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

    solution

    这道题设计状态比较难(对于我来说),但可以考虑一定是从上向下DP的,因此需要记录的状态只有这一行以及上一行(注意,只用记录两行,如果只用一维记录会无法记录状态,三维会MLE),上上行可以通过另一维来得到而且不会MLE

    用DP[L][S][i]表示当前是第i行,这一行状态是S,上一行状态是L,那么DP[L][S][i]=max(DP[L][S][i],DP[Fl][L][i-1]+sum[S]);   sum[S]表示S这个状态1的个数(即炮兵的个数)

    DP比较重要的是设置边界预处理,那么只需要处理前两行的DP值就可以了

    几点需要注意的:

    1.DP数组第三维需要滚动,不然MLE,考虑到一行的状态只跟上行和上上行有关,所以%3即可

    2.DP的优化:DP在枚举行的同时要枚举三个状态,如果放到最里面判断则O(n*23m),TLE妥妥的,因此每次枚举状态都进行判断,这样可以极大的缩短时间

    code

    #include<cstdio>
    #include<iostream>
    #define re register
    using namespace std;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int getsum(int x)
    {
        int ans=0;
        while(x)
        {
            if(x&1)
            ans++;
            x>>=1;
        }
        return ans;
    }
    int sum[1<<10],all,anss;
    int ans,sta[105],DP[1<<10][1<<10][3],n,m;
    char map[105][12];
    int main()
    {
        n=read();m=read();
        all=(1<<m)-1;
        for(re int i=0;i<n;++i)
         for(re int j=0;j<m;++j)
          {
              cin>>map[i][j];
              if(map[i][j]=='H')
              sta[i]|=(1<<(m-1-j));
          }
    //    for(re int i=0;i<n;++i)
    //    printf("%d
    ",sta[i]);
        for(int i=0;i<=all;++i)
         sum[i]=getsum(i);
        for(re int S=0;S<=all;++S)
         if(!(S&sta[0]||(S&(S<<1))||(S&(S<<2))))
          DP
        for(re int L=0;L<=all;++L)
          for(re int S=0;S<=all;++S)
           if(!(L&S||L&sta[0]||S&sta[1]||(L&(L<<1))||(L&(L<<2))||(S&(S<<1))||(S&(S<<2))))
            DP[L][S][1]=sum[S]+sum[L];
        for(re int i=2;i<n;++i)
         for(re int L=0;L<=all;++L)
         {
             if(L&sta[i-1]||(L&(L<<1))||(L&(L<<2))) continue;
             for(re int S=0;S<=all;++S)
             {
                 if(S&sta[i]||L&S||(S&(S<<1))||(S&(S<<2))) continue;
                 for(re int FL=0;FL<=all;++FL)
                 {
                     if(FL&L||FL&S||FL&sta[i-2]||(FL&(FL<<1))||(FL&(FL<<2))) continue;
                     DP[L][S][i%3]=max(DP[L][S][i%3],DP[FL][L][(i-1)%3]+sum[S]);
                 }
            }
         }
        for(re int L=0;L<=all;++L)
         for(re int S=0;S<=all;++S)
          anss=max(anss,DP[L][S][(n-1)%3]);
        printf("%d
    ",anss);
        return 0;
    }
  • 相关阅读:
    【水】希望之花
    如何不用狄利克雷卷积证明莫比乌斯函数性质二
    【数学】gcd
    挂分宝典
    [luogu P6042]「ACOI2020」学园祭 题解
    [luogu P6041]「ACOI2020」布丁暗杀计划 题解
    11.19模拟
    「CSP-S2020」题解
    11.11模拟
    「洛谷P1445」樱花
  • 原文地址:https://www.cnblogs.com/Liuz8848/p/10852533.html
Copyright © 2011-2022 走看看