poj -1185 炮兵阵地 (经典状压dp)

http://poj.org/problem?id=1185

参考博客:http://poj.org/problem?id=1185

大神博客已经讲的很清楚了,注意存状态的时候是从1开始的,所以初始化的时候也是dp[1][1][state],从0开始的话,状态就是dp[1][0][state]了.

dp[i][j][k]表示第i行状态为k第i-1行状态为j时的方案数.

dp[i][j][k]=max(dp[i][j][k],dp[i-1][t][j]+num[k]); (num[k]为k状态中1的个数)

边界条件:dp[1][1][i]=num[i],状态i可以满足第一行的条件。

还有就是为什么每一行最多只有60种状态,poj题目讨论里面有人给出了枚举的代码。

 1 #include <iostream>
 2 using namespace std;
 3 bool isok( int c ) {
 4     return !(c&(c<<1)||c&(c<<2));//同一行中不能有相邻的1距离小于3
 5 }
 6 int main() {
 7     int count=0;
 8     for( int i=0; i<1024; i++ )
 9         count += isok(i);
10     cout<<count<<endl;
11     return 0;
12 }
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cmath>
  4 #include <vector>
  5 #include <cstring>
  6 #include <string>
  7 #include <algorithm>
  8 #include <string>
  9 #include <set>
 10 #include <functional>
 11 #include <numeric>
 12 #include <sstream>
 13 #include <stack>
 14 //#include <map>
 15 #include <queue>
 16 #include <deque>
 17 //#pragma comment(linker, "/STACK:102400000,102400000")
 18 #define CL(arr, val)    memset(arr, val, sizeof(arr))
 19
 20 #define ll long long
 21 #define INF 0x7f7f7f7f
 22 #define lc l,m,rt<<1
 23 #define rc m + 1,r,rt<<1|1
 24 #define pi acos(-1.0)
 25
 26 #define L(x)    (x) << 1
 27 #define R(x)    (x) << 1 | 1
 28 #define MID(l, r)   (l + r) >> 1
 29 #define Min(x, y)   (x) < (y) ? (x) : (y)
 30 #define Max(x, y)   (x) < (y) ? (y) : (x)
 31 #define E(x)        (1 << (x))
 32 #define iabs(x)     (x) < 0 ? -(x) : (x)
 33 #define OUT(x)  printf("%I64d\n", x)
 34 #define lowbit(x)   (x)&(-x)
 35 #define Read()  freopen("a.txt", "r", stdin)
 36 #define Write() freopen("b.txt", "w", stdout);
 37 #define maxn 110
 38 #define maxv 5010
 39 #define mod 1000000000
 40 using namespace std;
 41 int n,m;
 42 char map[110][20],num[110],top;
 43 int stk[70],cur[110];
 44 int dp[110][70][70];
 45
 46 inline bool ok(int x) //判断该状态是否合法,即同一行不存在相邻1之间的距离小于3的
 47 {
 48     if(x&(x<<1)||x&(x<<2)) return 0;
 49     return 1;
 50 }
 51 inline void jnite() //找到所有可能合法的状态
 52 {
 53     top=0;
 54     int total=1<<m;
 55     for(int i=0;i<total;i++)
 56         if(ok(i)) stk[++top]=i;
 57 }
 58
 59 inline bool fit(int x,int k) //判断状态x是否与第k行匹配
 60 {
 61     if(cur[k]&x) return 0;
 62     return 1;
 63 }
 64 inline int jcount(int x) //计算一个整型数x的二进制中1的个数(用于初始化)
 65 {
 66     int cnt=0;
 67     while(x)
 68     {
 69         cnt++;
 70         x&=(x-1); //很精炼,每次都会与掉一个1
 71     }
 72     return cnt;
 73 }
 74 int main()
 75 {
 76     //Read();
 77     while(~scanf("%d%d",&n,&m))
 78     {
 79         if(n==0&&m==0) break;
 80         jnite();
 81         for(int i=1;i<=n;i++) scanf("%s",map[i]+1);
 82         for(int i=1;i<=n;i++)
 83         {
 84             cur[i]=0;
 85             for(int j=1;j<=m;j++)
 86             {
 87                 if(map[i][j]==‘H‘) cur[i]+=(1<<(j-1));
 88             }
 89             //printf("%d\n",cur[i]);
 90         }
 91         memset(dp,0,sizeof(dp));
 92         for(int i=1;i<=top;i++) //初始化第一行
 93         {
 94             num[i]=jcount(stk[i]);
 95             //printf("%d\n",num[i]);
 96             if(fit(stk[i],1)) dp[1][1][i]=num[i];
 97         }
 98         for(int i=2;i<=n;i++) {
 99             for(int t=1;t<=top;t++) {
100                 if(!fit(stk[t],i)) continue;//第i行是否冲突
101                 for(int j=1;j<=top;j++) {
102                     if(stk[t]&stk[j]) continue;//第i行和第i-2行是否冲突
103                     for(int k=1;k<=top;k++) {
104                         if(stk[t]&stk[k]) continue;//第i行和第i-1行是否冲突
105                         dp[i][k][t]=max(dp[i][k][t],dp[i-1][j][k]+num[t]);
106                       //  printf("%d\n",dp[i][k][t]);
107                     }
108                 }
109             }
110         }
111         int ans=0; //得到最大值
112         for(int i=1;i<=top;i++)
113             for(int j=1;j<=top;j++)
114             ans=max(ans,dp[n][i][j]);
115         printf("%d\n",ans);
116     }
117     return 0;
118 }
时间: 2024-11-05 16:39:13

poj -1185 炮兵阵地 (经典状压dp)的相关文章

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&

POJ 1185 炮兵阵地 (状压DP)

题目链接 题意 : 中文题不详述. 思路 :状压DP,1表示该位置放炮弹,0表示不放.dp[i][j][k],代表第 i 行的状态为k时第i-1行的状态为 j 时放置的最大炮弹数.只是注意判断的时候不要互相攻击到就可以了,还要与地形相适应. 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 6 using namespace std

poj 1185 炮兵阵地(状压DP)

炮兵阵地 \(solution:\) 这一道题限制条件有点多,我们需要逐个击破: 首先要判断这一格是否为山地,这个可以状态压缩 然后我们的左右一定距离不能有炮兵,这是一个突破口,因为我们看数据发现每行不超过十个格子!这样的话我们完全可以预处理出来每一行的填充方案而且这些方案肯定很少! 某一格的前面两格也不能有炮兵.这个限制最麻烦,他涉及了前两行,我们如果要从第一行开始向下推,那就必须知道前两行的所有情况!但是这些在极小的数据范围面前都可以想办法解决. 这是这道题的三个关键点,然后我们可以想到用前

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=

【POJ】1185 炮兵阵地(状压dp)

题目 传送门:QWQ 分析 看到$ M<=10 $考虑状压. 然后把每行都压一下,那么每个状态相关的就是上一行和上上行的状态. 然后枚举. 然后复杂度最坏是$ O(100 \times 1024^3) $的 仔细分析一下,有很多状态是无用的,但还是被判断了,比如$ 11111 $,显然不能做到不误伤. 那么我们把所有可能的状态拉出来(据说小于70?),即代码中的$ st $数组 然后用$ dp[i][j][k] $ 表示前i行上行状态st[j]本行状态st[k]的最大炮兵数量 最后统计答案时把最

[poj1185]炮兵阵地_状压dp

炮兵阵地 poj-1185 题目大意:给出n列m行,在其中添加炮兵,问最多能加的炮兵数. 注释:n<=100,m<=10.然后只能在平原的地方建立炮兵. 想法:第2到状压dp,++.这题显然是很经典的.设状态dp[i][j][k]表示第i行的状态为j,i-1行的状态为k的最多炮兵数.在转移时,枚举所有的合法炮兵排列(此处的合法数目是根据一行全为平原的时候能放置的合法炮兵数目),然后内层循环枚举dp[i-1]的i-1状态,进行特判更新即可.统计答案时,我们只需对于dp[n]的所有可能状态求最大值

poj1185:炮兵阵地(状压dp)

也算是比较基础的状压dp了,跟做过的第二道比较又稍微复杂了一点 需要记录之前两行的状态.. 统计结果也稍有不同 另外还学习了一个得到一个整数二进制位 1 的个数的位运算方法 详见代码: #include <iostream> #include <stdio.h> #include<string.h> #include<algorithm> #include<string> #include<ctype.h> using namespa

Poj 1185 炮兵阵地(状态压缩dp 入门题)

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

poj 1185 炮兵阵地 (状态压缩DP)

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