敌兵布阵 dp

题是看懂了,可是还是不会做,感觉太麻烦了,先放着吧。。。

点击打开链接

#include <cstdio>
#include <cmath>
#include <cstdlib>
const int large = (int)pow( 2, 10 );
 int n,m;
 char map[105][15];
 int dp[60][60][101];
 int ST[large+1];
 int len = 0;
 int Fun( int now, int last, int n )
 {
     int max = 0;
    int s = 0,i;
     int tmp = ST[now]|ST[last]; 
     if ( dp[now][last][n] != -1 ) return dp[now][last][n];
     for ( i = 0; i < m; ++i )
   {
        if ( (ST[now]&(~(1<<i))) != ST[now] ) ++s;
   }
    if ( n == 1 ) 
    {
          dp[now][last][1] = s;
          return s;
     }
    for (i = 0; i < len; ++i )
    {
         int flag = 1;
         int s = 0;
         if ( tmp&ST[i] ) continue; 
        for ( int j = 0; j < m; ++j ) 
         {
             if ( map[n-2][j] == 'H' && (ST[i]&(~(1<<j))) != ST[i] )
            {
                     flag = 0;
                     break;
             }
         }
        if ( flag ) max >?= Fun( last, i, n-1 ); 
    }
   max += s; 
     dp[now][last][n] = max;
    return max;
 }

bool OK( int a )
 {
     if ( a<0 || a>= m ) return false;
     else return true;
 }

int main()
{
    int power,ncase; 
    int max = 0;
        scanf( "%d%d", &n, &m );
        power = (int)pow( 2, m );
         
        
        for ( int i = 0; i < m; ++i ) map[0][i] = 'H';
         
       for ( int i = 1; i <= n; ++i )
       {
             scanf( "%s", map[i] );
        }
    
      
        for ( int i = 0; i < power; ++i )
       {
            int flag = 0;
           for ( int j = 0; j < m; ++j )
            {
               if ( (i&(~(1<<j))) != i )
                {
                     if ( OK(j-1) && (i&(~(1<<(j-1))))!=i ) 
                    {
                         flag = 1; 
                         break;
                    }
                    if ( OK(j-2) && (i&(~(1<<(j-2))))!=i )  
                      {
                         flag = 1; 
                         break;
                     }
                      if ( OK(j+1) && (i&(~(1<<(j+1))))!=i )
                    {
                          flag = 1; 
                          break;
                      }
                    if ( OK(j+2) && (i&(~(1<<(j+2))))!=i ) 
                     {
                          flag = 1; 
                          break;
                     }
               } 
           }
           if ( flag == 0 )
            {
                 ST[len++] = i;
            }
        }
        
     
       for ( int i = 0; i < 60; ++i )
       {
            for ( int j = 0; j < 60; ++j )
            {
                for ( int k = 0; k < 101; ++k )
                {
                    dp[i][j][k] = -1;
                }
            }
        }
    
      
        for ( int i = 0; i < len; ++i )
        {
           for ( int j = 0; j < len; ++j )
            {
                int flag = 1;
                if ( (ST[i]&ST[j]) ) continue; 
                for ( int k = 0; k < m; ++k )
                {
                    if ( map[n][k] == 'H' && (ST[i]&(~(1<<k)))!=ST[i] ) 
                    {
                        flag = 0;
                         break;
                   }
                    if ( map[n-1][k] == 'H' && (ST[j]&(~(1<<k)))!=ST[j] )
                    {
                         flag = 0;
                        break;
                    }
             }
               if ( flag ) max >?= Fun( i, j, n );
            }
        }
        printf( "%d\n", max );
   return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值