郑厂长系列故事——排兵布阵
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 以及平原阵地的具体地形,请你帮助郑厂长计算该阵地,最多能安排多少个士兵。
也不是副厂长
他根本就不是厂长
事实上
他是带兵打仗的团长
一天,郑厂长带着他的军队来到了一个n*m的平原准备布阵。
根据以往的战斗经验,每个士兵可以攻击到并且只能攻击到与之曼哈顿距离为2的位置以及士兵本身所在的位置。当然,一个士兵不能站在另外一个士兵所能攻击到的位置,同时因为地形的原因平原上也不是每一个位置都可以安排士兵。
现在,已知n,m 以及平原阵地的具体地形,请你帮助郑厂长计算该阵地,最多能安排多少个士兵。
Input
输入包含多组测试数据;
每组数据的第一行包含2个整数n和m (n <= 100, m <= 10 ),之间用空格隔开;
接下来的n行,每行m个数,表示n*m的矩形阵地,其中1表示该位置可以安排士兵,0表示该地形不允许安排士兵。
每组数据的第一行包含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; } }