zoukankan      html  css  js  c++  java
  • POJ_1185_炮兵阵地 dp+状态压缩

    题目:炮兵阵地

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

    解题思路:

      首先用 int 来表示每一行的情况,比如说第一行是k1,那么【 k1&(k1>>2) | k1&(k1>>1) 】就可以排除一行中相邻的和隔一格的。。。

      地形也可以用 int (取反)来表示,比如说第一行是PPHPH,给他记作m1=00101(二进制数),1表示不能存放,那么对于一个数a,判断a是不是符合地形就可以用【 a & m1 】来表示,如果与出来的是真,那么说明存在某一位1&1的情景,就表示不符合。

      下一行是否能和上一行共存也用位运算来进行,比如下一行是s2,上一行是s1,那么【 s2 & s1 】为真就表示不能共存。

      上面是通过位运算来巧妙解决可行存放问题的方法。

      贴代码了:

      

      1 #include<stdio.h>
      2 #include<string.h>
      3 /*
      4   改进。。。
      5 */
      6 char s[100][11];
      7 int mp[100];
      8 int ans[60],ao;
      9 int dp[100][60][60];
     10 /*
     11   dp[i][j][k]: 第i行 - 上一行是ans[j]、本行是ans[k]的情况下,最多数量为多少。
     12   因为有了两行的间隔,上面的炮台就不会影响到下面的,所以只要记录两行的所有情况,两行相同的可以计算出最大值了
     13 */
     14 //因为列数最多为10,所以无视地形,一行最多有60中存放方式
     15 void func(int m)
     16 {
     17   for(int i=0;i<(1<<m);i++)
     18   {
     19     if(i&(i>>1)||i&(i>>2)) continue;
     20     ans[ao++]=i;
     21   }
     22 }
     23 int count(int x)
     24 {
     25   int co=0;
     26   while(x)
     27   {
     28     co+=x&1;
     29     x>>=1;
     30   }
     31   return co;
     32 }
     33 int pre[100][10000],po,ko,lo;
     34 int main()
     35 {
     36   int n,m;
     37   while(scanf("%d%d",&n,&m)!=EOF)
     38   {
     39     for(int i=0;i<n;i++)
     40     {
     41       scanf("%s",s[i]);
     42     }
     43     memset(mp,0,sizeof(mp));
     44     for(int i=0;i<n;i++)
     45     {
     46       for(int j=0;j<m;j++)
     47       {
     48         if(s[i][j]=='H') mp[i]=mp[i]|(1<<j);
     49       }
     50     }
     51     ao=0;
     52     func(m);
     53     memset(dp,0,sizeof(dp));
     54     po=0;
     55     for(int i=0;i<ao;i++)
     56     {
     57       if(mp[0]&ans[i]) continue;
     58       int tmp=count(ans[i]);
     59       dp[0][0][i]=tmp;
     60       pre[0][po++]=i;   //记录第0行所有存值情况,po为总数
     61     }
     62     if(n==1)
     63     {
     64       int mt=0;
     65       for(int i=0;i<po;i++)
     66       {
     67         int line1=pre[0][i];  //因为前面只有一行,所以只需要考虑pre[0][i]的情况
     68         if(dp[0][0][line1]>mt) mt=dp[0][0][line1];
     69       }
     70       printf("%d
    ",mt);
     71       continue;
     72     }
     73     ko=0;
     74     for(int i=0;i<po;i++)
     75     {
     76       for(int j=0;j<ao;j++)
     77       {
     78         int line1=pre[0][i];
     79         if(ans[j]&mp[1]) continue;
     80         if(ans[line1]&ans[j]) continue;
     81         int tmp=count(ans[j]);
     82         dp[1][line1][j]=dp[0][0][line1]+tmp;
     83         pre[2][ko]=line1;  //到下一行时,这里就是上两行,下面的就是上一行,先用2暂存,最终再移入0
     84         pre[1][ko++]=j;
     85       }
     86     }
     87     for(int i=0;i<ko;i++)
     88       pre[0][i]=pre[2][i];
     89     bool v[70][70];
     90     for(int i=2;i<n;i++)
     91     {
     92       lo=0;
     93       memset(v,0,sizeof(v));
     94       for(int k=0;k<ko;k++)
     95       {
     96         int line1=pre[i-2][k],line2=pre[i-1][k];   //上两行和上一行的情况
     97         if(v[line1][line2]) continue;     //因为有很多重复的,去重
     98         v[line1][line2]=1;
     99         for(int u=0;u<ao;u++)
    100         {
    101           if(ans[u]&mp[i]) continue;  //如果与本身的地形不符,就跳过
    102           if(ans[u]&ans[line1]||ans[u]&ans[line2]) continue;  //如果和前两行矛盾就跳过
    103           int tmp=count(ans[u]);      //如果都满足条件,就计算这一行这种放法增加的数量
    104           if(dp[i-1][line1][line2]+tmp>dp[i][line2][u])
    105           {
    106             dp[i][line2][u]=dp[i-1][line1][line2]+tmp;
    107             pre[i+1][lo]=line2;       //先用i+1的存放,等k的循环结束再移到i-1
    108             pre[i][lo++]=u;
    109           }
    110         }
    111       }
    112       for(int u=0;u<lo;u++)
    113         pre[i-1][u]=pre[i+1][u];
    114       ko=lo;
    115     }
    116     int mt=0;
    117     for(int j=0;j<ko;j++)
    118     {
    119       int line1=pre[n-2][j],line2=pre[n-1][j];
    120       if(mt<dp[n-1][line1][line2]) mt=dp[n-1][line1][line2];
    121     }
    122     printf("%d
    ",mt);
    123   }
    124   return 0;
    125 }
  • 相关阅读:
    Spark参数优化
    Spark性能优化指南
    Durid的特点
    优秀博客地址
    Kylin的特点
    2017/11/20
    堆、栈、静态存储
    arraylist 和 linkedlist 的区别
    青岛项目遇到的问题
    access specifier
  • 原文地址:https://www.cnblogs.com/hchlqlz-oj-mrj/p/5058059.html
Copyright © 2011-2022 走看看