郑厂长系列故事——排兵布阵
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 1954 Accepted Submission(s): 701
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
题解:
1.曼哈顿距离:两点(x1,y1)(x2,y2)的曼哈顿距离为|x1-x2|+|y1-y2|;
2.假如一个点要安排士兵,我们要考虑的是曼哈顿距离为二的几个点是否会造成冲突,即若(x,y)安排人,则(x-2,y)(x-1,y+1),(x,y+2),(x+1,y+1),(x+2,y),(x+1,y-1),(x,y-2),(x-1,y-1)不能有人。然后就是状态方程了:dp[i][j][k] = Max(d[i][j][k],dp[i
- 1][k][l] + sum[j]);
My Code:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<string> #include<algorithm> #include<cstdlib> #include<set> #include<queue> #include<stack> #include<vector> #include<map> #define N 100010 #define Mod 10000007 #define lson l,mid,idx<<1 #define rson mid+1,r,idx<<1|1 #define lc idx<<1 #define rc idx<<1|1 const double EPS = 1e-11; const double PI = acos ( -1.0 ); const double E = 2.718281828; typedef long long ll; const int INF = 1000010; using namespace std; int cnt[250], sum[250];///保存在一行中所有符合情况的值 int mp[110];//用来表示每行的情况,1代表不能安排士兵,0可以 int len, n, m; int dp[110][250][250]; bool ok ( int x ) { if ( x & ( x << 2 ) ) return false;///同一行距离为2的有没有冲突 return true; } int getsum ( int x )///没有冲突的时候计算1的个数 { int ans = 0; while ( x > 0 ) { if ( x & 1 )//最后一位是1 ans++; x >>= 1;///右移一位 } return ans; } void finds()///算出所有符合情况的值 { len = 0; memset ( cnt, 0, sizeof cnt ); for ( int i = 0; i < ( 1 << m ); i++ ) { if ( ok ( i ) ) { cnt[len] = i; sum[len++] = getsum ( i ); } } //cout << len << endl; } int main() { //freopen("in.txt","r",stdin); while ( cin >> n >> m ) { //m = 10; finds(); int c; memset ( mp, 0, sizeof ( mp ) ); for ( int i = 0; i < n; i++ ) { for ( int j = 0; j < m; j++ ) { scanf ( "%d", &c );///为了方便计算,吧、把1存为0,把0存为1 if ( !c ) mp[i] |= ( 1 << j ); } } memset ( dp, -1, sizeof ( dp ) ); for ( int i = 0; i < len; i++ )///先处理第一行 { if ( ! ( cnt[i]&mp[0] ) ) dp[0][i][0] = sum[i]; } for ( int i = 1; i < n; i++ ) { for ( int j = 0; j < len; j++ ) { if ( cnt[j]&mp[i] )///与mp[i]有冲突 continue; for ( int k = 0; k < len; k++ )///i-1行的情况 { if ( ( ( cnt[k] << 1 ) &cnt[j] ) || ( ( cnt[k] >> 1 ) &cnt[j] ) ) continue;///左右一个单位的对角上有人的情况 for ( int l = 0; l < len; l++ )///i-2行 { if ( cnt[j]&cnt[l] )///第i行与第2行有冲突 continue; if ( ( ( cnt[l] << 1 ) &cnt[k] ) || ( ( cnt[l] >> 1 ) &cnt[k] ) ) continue;///i-1行与i-2行 if ( dp[i - 1][k][l] == -1 ) continue; if ( dp[i - 1][k][l] + sum[j] > dp[i][j][k] ) dp[i][j][k] = dp[i - 1][k][l] + sum[j]; } } } } int ans = -1; for ( int i = 0; i < len; i++ ) for ( int j = 0; j < len; j++ ) if ( ans < dp[n - 1][i][j] ) ans = dp[n - 1][i][j]; cout << ans << endl; } return 0; }