zoukankan      html  css  js  c++  java
  • 【NOI2001】炮兵阵地

    【题目描述】

    司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击 范围如图中黑色区域所示:

    如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。

    现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

                           

    【输入文件】

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

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

    【输出文件】

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

    【分析】

    这是一道经典的状态压缩类动态规划的题目。

    我们可以看到表示列数的M(M<=10)很小,考虑用一个数的二进制位0与1来表示是否放置炮兵,同时我们用0来表示高低,1来表示平原,用map[i]来记录。

    我们发现,因为炮兵的范围可以延伸到两行,所以我们在考虑L行的状态时,总要根据L-1行与L-2行来推得,于是,我们想到要先将所有可的状态通过枚举得出来(即满足同行两个炮兵互不攻击),并用state[i]来记录,同时我们也需要把每行所摆的炮兵数用Count[i]记录,注意第一行要特殊处理

    完成了以上的准备工作,用F[i][J][k]来表示在第i行采用第j个状态,上一行采用第k个状态所能得到的最大炮兵数,于是我们很容易得到状态转移方程:

    满足state[k1]&state[j]==0  &&  state[k2]&state[j]==0 && map[i]|state[j]==map[i]

    f[i][j][k1]=max(f[i][j][k1],f[i-1][k1][k2]+Count[j])

    需满足条件中三个条件所代表的意义分别是,I行与I-1行、I-2行均不冲突,且与地形不冲突,然后就可以转移状态了。

     1 #include <cstdlib>
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <cstring>
     7 const int maxn=105;
     8 using namespace std;
     9 int n,m,map[maxn],size;
    10 int f[maxn][maxn][maxn];
    11 int Count[maxn],state[maxn];
    12 
    13 void prepare();
    14 void dp();
    15 
    16 int main()
    17 {
    18     int i,j;
    19     //文件操作
    20     freopen("cannon.in","r",stdin);
    21     freopen("cannon.out","w",stdout);
    22     
    23     scanf("%d%d",&n,&m);
    24     for( int i = 1; i <= n; i ++ ){
    25         char str[20];
    26         scanf("%s", str);
    27         for( int j = 0; j < m; j ++ ){            
    28             if( str[j] == 'P' )
    29                 map[i] = (map[i]<<1)+1;
    30             else map[i] = (map[i]<<1)+0;
    31         }
    32     }
    33     prepare();//预处理第一行 
    34     dp();//状态转移 
    35     int ans=0;
    36     for (i=0;i<size;i++)
    37     for (j=0;j<size;j++)
    38     ans=max(ans,f[n][i][j]);
    39     
    40     printf("%d
    ",ans);
    41     return 0;
    42 }
    43 void prepare()
    44 {
    45      int i;//记录状态个数 
    46      memset(f,0,sizeof(f));
    47      
    48      for (i=0;i<(1<<m);i++)
    49      {
    50          //flag代表是否可以摆 
    51          int cnt=0,temp=i,flag=0;
    52          while (temp>0){
    53                //摆了 
    54                if ((temp&1)==1){
    55                    if (flag>0) break;
    56                    else flag=2;//放上比较 
    57                    cnt++;//用来统计本行放上的炮兵个数 
    58                }
    59                else flag--;
    60                temp=temp>>1;
    61          }
    62          if (temp==0)//可以摆
    63          {
    64               Count[size]=cnt;
    65               //表示地形可以摆放 
    66               if ((map[1]|i)==map[1])
    67               f[1][size][0]=cnt;
    68               //累计状态 
    69               state[size++]=i;
    70          } 
    71      }
    72      return;
    73 }
    74 void dp()
    75 {
    76      int i,k1,k2,j;
    77      for (i=2;i<=n;i++)//决策行 
    78      for (k1=0;k1<size;k1++)//上一行 
    79      for (k2=0;k2<size;k2++)//上两行
    80      if (f[i-1][k1][k2]>0)//上两行的摆放状态是合理的 
    81      {
    82          for (j=0;j<size;j++)
    83          //查看当前摆放状态与上两行是否冲突 
    84          if ((state[k1]&state[j])==0 && (state[k2]&state[j])==0)
    85          if ((map[i]|state[j])==map[i])
    86          f[i][j][k1]=max(f[i][j][k1],f[i-1][k1][k2]+Count[j]);
    87      } 
    88 }
    View Code
  • 相关阅读:
    关于这个 blog
    P6499 [COCI2016-2017#2] Burza 题解
    CF1172F Nauuo and Bug 题解
    CF1479D Odd Mineral Resource 题解
    CF1442E Black, White and Grey Tree 题解
    CF1442D Sum 题解
    CF1025D Recovering BST 题解
    CF1056E Check Transcription 题解
    CF1025F Disjoint Triangles 题解
    红包算法的PHP实现
  • 原文地址:https://www.cnblogs.com/hoskey/p/3737870.html
Copyright © 2011-2022 走看看