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
", 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
",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
",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
",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
",ans);
116     }
117     return 0;
118 }
原文地址:https://www.cnblogs.com/nowandforever/p/4717523.html