[2013腾讯马拉松复赛第二场] HDU 4539 郑厂长系列故事——排兵布阵

以后做比赛前一定补好睡眠,没有精神A不动题目……,最后一题的题意到2H才发现看错了,原来是要求曼哈顿距离等于2的而不是小于等于2的……,调了半天样例都输出1……。最后只AC了2题,第一个和最后一个,第二个怎么想怎么是爆搜,是不是爆搜?

最后一题排兵布阵是比较经典的状压DP,看群里还有用点独立集做的,还有用插头DP做的?ORZ。

做法跟POJ 1185炮兵阵地,这道经典状压DP神似,连题目都神似。所以具体转移方程也基本一样,需要枚举前两行的状态。具体细节不明白的可以先去搜poj 1185的解题报告。

题目虽然给的时间很多,但是比赛怕超时就先预处理了所有当前行可行的状态。判断当前行k,和k-2行是否兼容跟炮兵阵地的处理方式一样,直接相与。处理k跟k-1行略有不同,是把k-1行的状态搓一个位(其实就是乘2,除2)相与,看这两个结果有没有不等于0的。其他都跟炮兵一样。

View Code
  1 #include <set>
  2 #include <list>
  3 #include <queue>
  4 #include <stack>
  5 #include <cmath>
  6 #include <ctime>
  7 #include <vector>
  8 #include <bitset>
  9 #include <cstdio>
 10 #include <string>
 11 #include <numeric>
 12 #include <cstring>
 13 #include <cstdlib>
 14 #include <iostream>
 15 #include <algorithm>
 16 #include <functional>
 17 using namespace std;
 18 typedef long long ll;
 19 #define Exp 1e-8
 20 #define inf 0x7fffffff
 21 #define read freopen("in.txt","r",stdin)
 22 #define write freopen("out.txt","w",stdout)
 23 #define maxn 200
 24 int n,m,top;
 25 int map[105][12],con[maxn][maxn],con2[maxn][maxn];
 26 int state[maxn][2],vm[105],dp[105][maxn][maxn];
 27 int max(int a,int b)
 28 {
 29     if(a>b)return a;
 30     return b;
 31 }
 32 void prt(int i)
 33 {
 34     int t=i;while(t)printf("%d",t%2),t>>=1;puts("");
 35 }
 36 bool check(int a,int b)//判断当前行的状态能否放入地图中
 37 {
 38     if(((~b)&a))return false;
 39     return true;
 40 }
 41 void init()//预处理一行能够放士兵的状态
 42 {
 43     int i,j;
 44     memset(state,0,sizeof(state));
 45     top=0;
 46     for(i=0;i<(1<<10)-1;++i)
 47     {
 48         if((i&(i<<2)))continue;
 49         state[top][0]=i;//0存放状态,1统计个数
 50         for(j=i;j;j-=j&(-j))state[top][1]++;
 51         ++top;//prt(state[top-1][0]);
 52     }
 53     for(i=0;i<top;++i)for(j=0;j<top;++j)//con[i][j]表示当前行跟上一行状态为i,j是否能共存
 54         con[i][j]=!(state[i][0]&state[j][0]);
 55     for(i=0;i<top;++i)for(j=0;j<top;++j)//con[i][j]表示当前行跟上二行状态为i,j是否能共存
 56     {
 57         int t1=state[i][0]&(state[j][0]<<1);
 58         int t2=state[i][0]&(state[j][0]>>1);
 59         con2[i][j]=!(t1|t2);
 60     }
 61 }
 62 int main()
 63 {
 64     //read;
 65     init();
 66     int i,j,k,s;
 67     while(~scanf("%d%d",&n,&m))
 68     {
 69         memset(vm,0,sizeof(vm));
 70         memset(map,0,sizeof(map));
 71         memset(dp,0,sizeof(dp));
 72         for(i=0;i<n;++i)
 73         {
 74             for(j=0;j<m;++j)
 75             {
 76                 scanf("%d",&map[i][j]);
 77                 vm[i]=(vm[i]+map[i][j])<<1;
 78             }
 79             vm[i]>>=1;//地图信息状态压缩
 80         }
 81         for(i=0;i<top;++i)
 82         {
 83             if(check(state[i][0],vm[0])==0)continue;
 84             for(j=0;j<top;j++)dp[0][i][j]=state[i][1];
 85         }
 86         for(i=0;i<top;++i)
 87         {
 88             if(check(state[i][0],vm[1])==0)continue;
 89             for(j=0;j<top;j++)
 90             {
 91                 if(check(state[j][0],vm[0])==0)continue;
 92                 if(con2[i][j]==0)continue;
 93                 dp[1][i][j]=max(dp[1][i][j],dp[0][j][0]+state[i][1]);
 94             }
 95         }
 96         for(s=2;s<n;++s)
 97             for(i=0;i<top;++i)
 98             {
 99                 if(check(state[i][0],vm[s])==0)continue;
100                 for(j=0;j<top;++j)
101                 {
102                     if(check(state[j][0],vm[s-1])==0)continue;
103                     if(con2[i][j]==0)continue;
104                     for(k=0;k<top;++k)
105                     {
106                         if(check(state[k][0],vm[s-2])==0)continue;
107                         if(con2[j][k]==0||con[i][k]==0)continue;
108                         dp[s][i][j]=max(dp[s][i][j],state[i][1]+dp[s-1][j][k]);
109                     }
110                 }
111             }
112         int ans=0;
113         for(i=0;i<top;++i)for(j=0;j<top;++j)ans=max(ans,dp[n-1][i][j]) ;
114         printf("%d\n",ans);
115     }
116     return 0;
117 }
原文地址:https://www.cnblogs.com/mcflurry/p/2991018.html