hdu 4539 郑厂长系列故事——排兵布阵

郑厂长系列故事——排兵布阵

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 1294    Accepted Submission(s): 470


Problem Description
  郑厂长不是正厂长
  也不是副厂长
  他根本就不是厂长
  事实上
  他是带兵打仗的团长

  一天,郑厂长带着他的军队来到了一个n*m的平原准备布阵。
  根据以往的战斗经验,每个士兵可以攻击到并且只能攻击到与之曼哈顿距离为2的位置以及士兵本身所在的位置。当然,一个士兵不能站在另外一个士兵所能攻击到的位置,同时因为地形的原因平原上也不是每一个位置都可以安排士兵。
  现在,已知n,m 以及平原阵地的具体地形,请你帮助郑厂长计算该阵地,最多能安排多少个士兵。
 

 

Input
输入包含多组测试数据;
每组数据的第一行包含2个整数n和m (n <= 100, m <= 10 ),之间用空格隔开;
接下来的n行,每行m个数,表示n*m的矩形阵地,其中1表示该位置可以安排士兵,0表示该地形不允许安排士兵。
 

 

Output
请为每组数据计算并输出最多能安排的士兵数量,每组数据输出一行。
 

 

Sample Input
6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 

 

Sample Output
2
 

 

Source
// ans[] 里面存的是 m 个 1 能达到所有的状态 
//如果 m == 2 , 则可以达到 00 01 10 11 既0,1,2,3
// dp[i][j][k] 表示 计算到 第 i 行 状态是 ans[j] , 上一行 状态是 ans[k] ;
// 然后枚举上一行的所有状态 和上一行判断是否有冲突 ,
//可以把上一行的状态 向左和向右移一位(二进制),判断是否有同 1
// 和上一行的上一行只要判断是否同为一就好了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<set>
#include<algorithm>
#define maxn 110
#define INF 100
#define LL long long
#define mod 1000000007
using namespace std ;

int len , f[14],m ,num[200],n;
int ans[200] , dp[110][172][172] ;
bool vi[1025] , map1[110][11] ;
void dfs( int cur , int sum , int a , int mm )
{
    if(cur > m )
    {
         num[len] = mm ;
         ans[len++] = sum ;
        return ;
    }
    dfs(cur+1,sum,a+1,mm) ;
    if(cur >= 3 && f[cur-2] == 1 ) return ;
    f[cur] = 1 ;
    dfs(cur+1,sum+(1<<a),a+1,mm+1) ;
    f[cur] = 0 ;
}
int get( int cur )//返回cur 行可以达到最大的状态值是多少
{
    int ans = 0, i;
    for( i = 0 ; i < m ;i++ )
    {
        if(map1[cur][i+1]) ans += (1<<i) ;
    }
    return ans ;
}
bool check1( int b , int a )
{
    int a1 , a2 ;
    a1 = a<<1 ;a2 = a>>1 ;
    if((a1&b)||(a2&b)) return false ;
    return true ;
}
bool check2( int a , int b )
{
    if(a&b) return false ;
    return true ;
}
int main()
{
    int i , j ,aa , bb , k , v ;
    int Max ;
     //freopen("in.txt","r",stdin) ;
    while( scanf("%d%d" , &n , &m ) != EOF )
    {
        len = 1 ;
        memset(f,0,sizeof(f)) ;
        //枚举所有状态
        dfs(1,0,0,0) ;
        sort(ans+1,ans+len) ;
      //  for( i = 1 ; i < len ;i++)cout << ans[i] << " " ;
        for( i = 1 ; i <= n ;i++ )
            for( j = 1 ; j <= m ;j++ )
        {
            scanf("%d",&aa) ;
            if(aa==1)map1[i][j] = 1 ;
            else map1[i][j] = 0 ;
        }
        bb = get(1) ;
        Max = 0 ;
        memset(dp,0,sizeof(dp)) ;
        for( i = 1 ; i < len ;i++ )if((ans[i]|bb) <= bb )//如果 ans[i] 可达, 既 bb 为一的 ans[i] 可以为 1 ,为0 的 ans[i] 只可以为 0
        {
            for( j = 1 ; j < len ;j++ )
               dp[1][i][j] = num[i] ;
        }
        for( i = 2 ; i <= n ;i++ )
            for( j = 1 ; j < len ;j++ )
        {
            bb = get(i) ;
            if((bb|ans[j]) > bb )continue ;
            for( k = 1 ; k < len ;k++ )if(check1(ans[j],ans[k])||bb==0)
                for( v = 1 ; v < len ;v++ )if(check2(ans[j],ans[v])||bb==0){
                    dp[i][j][k] = max(dp[i][j][k],dp[i-1][k][v]+num[j]) ;

                }
        }
        for( i = 1 ; i < len ;i++ )
            for( j = 1 ; j < len ;j++ )
            Max = max(Max,dp[n][i][j]) ;
     cout << Max << endl;
    }
}

 

posted @ 2013-10-25 10:05  _log__  阅读(221)  评论(0编辑  收藏  举报