PKU 1185 炮兵阵地

"N <= 100;M <= 10"

这个形状基本就是状态压缩DP的标志(一个几百左右, 一个十几左右).

一层一层往下DP, 每层只受前两层影响, 经过计算, 每层最多有60种状态, 固复杂度为O(603*100).

详情见代码:

#include  < iostream >
using   namespace  std;

#define  max(a, b)   ((a)>(b)?(a):(b))

int  n, m;
char  mat[ 100 ][ 11 ];
int  sta[ 60 ], sta_sum[ 60 ], sta_cnt;    // 二进制状态; 每个二进制状态中1的个数; 总状态数
int  pre[ 60 ][ 60 ], now[ 60 ][ 60 ];

int  get_1( int  x)  // 统计二进制中1的个数 
{
    
int  k;
    
for  (k  =   0 ; x; k ++ ) x  &=  (x  -   1 );
    
return  k;
}

void  get_sta( int  space,  int  pre,  int  i)  // 计算单行所有可能的状态 
{
    
if  (i  ==  m)
    {
        sta[sta_cnt] 
=  pre;
        sta_sum[sta_cnt
++ =  get_1(pre);
        
return ;
    }

    get_sta(space
+ 1 , pre, i + 1 );
    
if  (space  >   1 )
        get_sta(
0 , pre | 1 << i, i + 1 );
}

void  recur( int  row)
{
    
int  hill  =   0 ;    // 把单行的山转化成二进制 
     for  ( int  i  =   0 ; i  <  m; i ++ )
        
if  (mat[row][i]  ==   ' H ' )
            hill 
+=   1 << i;
    
    
for  ( int  i  =   0 ; i  <  sta_cnt; i ++ )    // 状态转移 
    {
        
if  (sta[i]  &  hill)  continue ;
        
for  ( int  j  =   0 ; j  <  sta_cnt; j ++ )
        {
            
for  ( int  k  =   0 ; k  <  sta_cnt; k ++ )
            {
                
if  (sta[i] & sta[j]  ||  sta[j] & sta[k]  ||  sta[i] & sta[k])  continue ;
                now[i][j] 
=  max(now[i][j], pre[j][k]);
            }
            now[i][j] 
+=  sta_sum[i];
        }
    }
}

int  main()
{
    scanf(
" %d %d " & n,  & m);
    
for  ( int  i  =   0 ; i  <  n; i ++ )
        scanf(
" %s " , mat[i]);
    
    get_sta(
2 0 0 );
    
    
for  ( int  i  =   0 ; i  <  n; i ++ )
    {
        recur(i);
        memcpy(pre, now, 
sizeof (now));
        memset(now, 
0 sizeof (now));
    }
    
    
int  ans  =   0 ;
    
for  ( int  i  =   0 ; i  <  sta_cnt; i ++ )
        
for  ( int  j  =   0 ; j  <  sta_cnt; j ++ )
            ans 
=  max(ans, pre[i][j]);
            
    printf(
" %d\n " , ans);
    
return   0 ;
}

你可能感兴趣的:(pku)