POJ 1185 炮兵阵地 (状压DP,轮廓线DP)

题意:

  给一个n*m的矩阵,每个格子中有'P'或者'H',分别表示平地和高原,平地可以摆放大炮,而大炮的攻击范围在4个方向都是2格(除了自身位置),攻击范围内不能有其他炮,问最多能放多少个炮?(n<=100,m<=10)

思路:

  明显需要记录到最顶上的2格,所以一共需要记录2*m个格子有没有放炮,2*m<=20,这个数字还是很大的。但是由于炮的攻击范围比较大,所以能放得下的炮比较少,也就意味着状态比较少,那么只要不用枚举[0,1<<2*m)这么大的范围都是可以解决的。即使n=100且m=10,状态数仍然很小。弄个哈希模板就解决了。

  1 //#include <bits/stdc++.h>
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cmath>
  6 #include <map>
  7 #include <algorithm>
  8 #include <vector>
  9 #include <iostream>
 10 #define pii pair<int,int>
 11 #define INF 0x7f3f3f3f
 12 #define LL long long
 13 #define ULL unsigned long long
 14 using namespace std;
 15 const double PI  = acos(-1.0);
 16 const int N=105;
 17 
 18 struct Hash_Map{
 19     static const int mod=1237;  //根据状态数设计的哈希函数
 20     static const int N=10000;   //状态数
 21     int head[mod];      //桶指针
 22     int next[N];        //记录链的信息
 23     int status[N];      //状态
 24     int value[N];       //状态对应的DP值。
 25     int size;           //状态数
 26     void clear(){    //每次调用都要清除哈希表中的状态
 27         memset(head, -1, sizeof(head));
 28         size = 0;
 29     }
 30     void insert(int st, int val){  //插入状态st的值为val
 31         int h = st%mod;
 32         for(int i=head[h]; i!=-1; i=next[i]){
 33             if(status[i] == st){ //这个状态已经存在,累加进去。
 34                 value[i] = max(value[i], val);
 35                 return ;
 36             }
 37         }
 38         status[size]=st;    value[size]=val;//找不到状态st,则插入st。
 39         next[size]=head[h]; head[h]=size++; //新插入的元素在队头
 40     }
 41 }hashmap[2];
 42 
 43 char g[N][14];
 44 
 45 
 46 
 47 int cal(int n,int m)
 48 {
 49     int cur=0, mod=1<<2*m-1;
 50     hashmap[0].clear();
 51     hashmap[0].insert(0,0);
 52     for(int i=1; i<=n; i++)
 53     {
 54         for(int j=1; j<=m; j++)
 55         {
 56             cur^=1;
 57             hashmap[cur].clear();
 58             for(int k=0; k<hashmap[cur^1].size; k++)
 59             {
 60                 int s=hashmap[cur^1].status[k];
 61                 int v=hashmap[cur^1].value[k];
 62                 int t=(s&(mod-1))<<1;
 63                 //cout<<"123"<<endl;
 64                 if(g[i][j]=='P')    //可以放炮
 65                 {
 66                     if(s&(1<<2*m-1))    //上2
 67                         hashmap[cur].insert(t,v);
 68                     else if(s&(1<<m-1)) //上1
 69                         hashmap[cur].insert(t,v);
 70                     else if(j>2&&s&2)   //左2
 71                         hashmap[cur].insert(t,v);
 72                     else if(j>1&&s&1)    //左1
 73                         hashmap[cur].insert(t,v);
 74                     else    //可防可不放
 75                     {
 76                         hashmap[cur].insert(t,v);
 77                         hashmap[cur].insert(t+1,v+1);
 78                     }
 79                 }
 80                 else    hashmap[cur].insert(t,v);
 81             }
 82         }
 83     }
 84     int ans=-1;
 85     for(int i=0; i<hashmap[cur].size; i++)
 86         ans=max(ans,hashmap[cur].value[i]);
 87     return ans;
 88 }
 89 
 90 int main()
 91 {
 92     //freopen("input.txt","r",stdin);
 93     int n, m;
 94     while(~scanf("%d%d",&n,&m))
 95     {
 96         for(int i=1; i<=n; i++)    scanf("%s",g[i]+1);
 97         printf("%d
",cal(n,m));
 98     }
 99     return 0;
100 }
AC代码
原文地址:https://www.cnblogs.com/xcw0754/p/4858618.html