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\n",cal(n,m));
 98     }
 99     return 0;
100 }

AC代码

  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\n",cal(n,m));
 98     }
 99     return 0;
100 }

AC代码

时间: 2024-08-05 19:35:36

POJ 1185 炮兵阵地 (状压DP,轮廓线DP)的相关文章

POJ 1185 炮兵阵地 状压dp

http://poj.org/problem?id=1185 经典题目不必多说,直接贴代码. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int n, m, cnt, size; 7 int a[110], st[70], ct[70]; 8 char str[15]; 9 int f[110][70][70]; 10 void init(

POJ 1185 炮兵阵地 状压DP+离散化优化

一开始能想到的状态就只有位压两行和当前行的行号,这样无论是空间和时间都是无法接受的. 但是因为炮兵的攻击范围比较大,而且又有地形限制,每一行的状态其实不多了,打表看了一下不超过80种,离散化一下就可以随意DP了. 据说题目也可以抽象成二分图最大匹配来搞?感觉复杂度有点高 #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set> #i

POJ 1185 炮兵阵地 (状压dp 经典中的经典)

炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 21381   Accepted: 8290 Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队):一支炮兵部队在地图上的攻击

POJ 1185炮兵阵地 (状压DP)

题目链接 POJ 1185 今天艾教留了一大堆线段树,表示做不动了,就补补前面的题.QAQ 这个题,我第一次写还是像前面HDU 2167那样写,发现这次影响第 i 行的还用i-2行那样,那以前的方法就行不通了. 找出所有可行的状态,因为每一行最大只有10列,所以一行里最多有4个,那它可行的状态不多(网上大多数说法最多是60个).用dp[x][i][j]来转移,x表示第x行,i表示第x行的状态,j表示第x-1行的状态.先初始化前两行. 1 #include <cstdio> 2 #include

poj - 1185 炮兵阵地 状压DP 解题报告

炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 21553   Accepted: 8363 Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示).也可能是平原(用"P"表示),例如以下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不可以部署炮兵部队).一支炮兵部队在地图上的

[poj 1185] 炮兵阵地 状压dp 位运算

Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队 (山地上不能够部署炮兵部队):一支炮兵部队在地图上的攻击范围如图中黑色区域所示: 如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格.图上其它白色网格均攻击

POJ 1185 炮兵布阵 状压DP

链接:http://poj.org/problem?id=1185 题意:一个地图上有两种地形,H和P,P上可以放一个炮,攻击范围是上下左右各两格,问的是最多可以再地图上放多少个炮.行N <= 100,列M <= 10. 思路:因为上下左右各两格内不能放置炮,所以每一行的状态数从2^10减少到60种.状态转移方程为:dp[i][j][k]=max(dp[i-1][k][l]+bb[j]).dp[i][j][k]表示在第i行状态为j,在第i-1行状态为k的前i行一共放置的炮塔数.bb[j]表示状

poj1185炮兵阵地状压dp

压前两行的状态很容易想到,但是 直接搞  (1<<10) * (1<<10)  空间时间都明显受不了, 但是经过高人指点,你会发现:枚举每一行可行的状态,其实并不多,预先打表处理,不用 1->(1<<10)枚举每一种状态.. 然后记忆化搜就ok了. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include &

POJ 1185 炮兵阵地(动态规划)

炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 19152   Accepted: 7417 Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队):一支炮兵部队在地图上的攻击

POJ 1185 炮兵阵地(状压DP入门)

http://poj.org/problem?id=1185 状压DP: 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int dp[105][100][100]; 7 int ma[105],st[105]; 8 9 int ok(int x) 10 { 11 return (x&(x<<1))+(x&(x&