2010年1月13日星期三.pku1185 状态压缩动态规划

2010年1月13日星期三.pku1185 状态压缩动态规划

2010年1月13日星期三.pku1185
状态压缩动态规划

pku1185:题目是中文的,而且题目很经典,题意不再赘述。

这个题目比pku2411和sgu131两题来说多了一行状态需要储存
因为如果上上行和此行有关
而且此题不再是求完美覆盖的方式,而是求能最大的放置个数。

方法是先求出一行中的所有放置方法。
然后逐行递推,然后在递推的过程中枚举当前行状态,如果和上两行不冲突的话,就
进行放置个数的更新

f[N][60][60] //N行,上一行的状态号,上上行的状态号

具体看代码吧
  1 
  2  /*
  3   * SOUR:pku1185
  4   * ALGO:State Compression DP
  5   * DATE: 2010年 01月 13日 星期三 13:57:49 CST
  6   * COMM:4  http://www.cppblog.com/schindlerlee
  7   *  */
  8  #include < iostream >
  9  #include < cstdio >
 10  #include < cstdlib >
 11  #include < cstring >
 12  #include < algorithm >
 13  using   namespace  std;
 14  typedef  long   long  LL;
 15  const   int  maxint  =   0x7fffffff ;
 16  const   long   long  max64  =  0x7fffffffffffffffll;
 17 
 18  #define  bin(i) (1 << (i))
 19  #define  low(i) ((i) & -(i))
 20  #define  SL(i) ((i) << 1)
 21  #define  SR(i) ((i) >> 1)
 22 
 23  void  ckmax( int   & a,  int  b)
 24  if  (a  <  b) a  =  b; }
 25 
 26  const   int  N  =   102 ;
 27  const   int  M  =   10 ;
 28 
 29  // 60是对M==10的一行进行深搜得到的最大状态数量
 30  int  f[N][ 60 ][ 60 ], n, m, terrain[N], full;
 31  int  s[ 60 ], top, c[ 60 ];
 32 
 33  int  legal( int  x)
 34  {
 35       int  b  =   0 , cnt  =   0 , c;
 36       while  (x  >   0 ) {
 37          cnt ++ ;
 38          c  =  low(x);
 39           if  (SL(b)  &  x  ||  SL(SL(b))  &  x) {
 40               return   - 1 ;
 41          }
 42          x  ^=  c;
 43          b  =  c;
 44      }
 45       return  cnt;
 46  }
 47 
 48  void  preprocess()
 49  {
 50       int  i, j, cnt;
 51       for  (i  =   0 ; i  <=  full; i ++ ) {
 52           if  ((cnt  =  legal(i))  >=   0 ) {
 53              s[top]  =  i, c[top]  =  cnt, top ++ ;
 54          }
 55      }
 56  }
 57 
 58  bool  contradict( int  cur,  int  s1,  int  s2)
 59  return  (cur  &  s1)  ||  (cur  &  s2); }
 60 
 61  int  main()
 62  {
 63       int  i, j, k;
 64       char  str[ 12 ];
 65       while  (scanf( " %d%d\n " & n,  & m)  ==   2 ) {
 66          full  =  bin(m)  -   1 ;
 67          preprocess();
 68 
 69           for  (i  =   1 ; i  <=  n; i ++ ) {
 70              scanf( " %s\n " , str);
 71               int  tmp  =   0 ;
 72               for  (j  =   0 ; j  <  m; j ++ ) {
 73                  tmp  <<=   1 ;
 74                   if  (str[j]  ==   ' H ' ) {
 75                      tmp  |=   1 ;
 76                  }
 77              }
 78              terrain[i]  =  tmp;
 79          }
 80 
 81           for  (i  =   1 ; i  <=  n; i ++ ) {
 82               for  (j  =   0 ; j  <  top; j ++ ) {  // 枚举当前行
 83                   int  cur  =  s[j], curcnt  =  c[j];
 84                   if  (cur  &  terrain[i]) {
 85                       continue ;
 86                  }     // 不符合第i行地形要求
 87 
 88                   for  ( int  k1  =   0 ; k1  <  top; k1 ++ ) {  // 枚举前两行
 89                       for  ( int  k2  =   0 ; k2  <  top; k2 ++ ) {
 90                           if  ( ! contradict(cur, s[k1], s[k2])) {  // 和上两行状态不冲突
 91                              ckmax(f[i][j][k1], f[i  -   1 ][k1][k2]  +  curcnt);
 92                          }
 93                      }
 94                  }
 95              }
 96          }
 97 
 98           int  res  =   0 ;
 99           for  (i  =   0 ; i  <  top; i ++ ) {
100               for  (j  =   0 ; j  <  top; j ++ ) {
101                  ckmax(res, f[n][i][j]);
102              }
103          }
104          printf( " %d\n " , res);
105      }
106       return   0 ;
107  }
108 
109 


你可能感兴趣的:(2010年1月13日星期三.pku1185 状态压缩动态规划)