题意:在N*M的网格地图上部署炮兵部队。地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:
![](https://i-blog.csdnimg.cn/blog_migrate/ba1d4fa736b99550a7ee43784c287df9.jpeg)
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域。炮兵的攻击范围不受地形的影响。
现在,如何部署炮兵部队,使得任何一支炮兵部队都不在其他支炮兵部队的攻击范围内,在整个地图区域内最多能够摆放多少我军的炮兵部队。
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string>
using namespace std;
/** 每行摆放炮兵的方法数的最大值 */
#define INF 70
/** 总行数的最大值 */
#define nMAX 103
/** 每一行炮兵的合法的摆放状态 */
int state[INF];
/** 每一种摆放方法的炮兵,state[i]这一摆放方法中炮兵总数为count[i] */
int count[INF];
/** f[i][j][k] 表示在上一行以state[k] 的方法摆放的前提下,第i 行以state[j] 的方法摆放的方法总数 */
int f[nMAX][INF][INF];
/** map数组是输入的地形数据的压缩 */
int map[nMAX];
int main()
{
/** n * m 的网格地图 */
int m, n;
scanf("%d%d", &n, &m);
/** 对输入的地形数据压缩存储 */
for( int i = 1; i <= n; i ++ ){
char str[20];
scanf("%s", str);
for( int j = 0; j < m; j ++ ){
if( str[j] == 'P' )
map[i] = ( map[i] << 1 ) + 1;
else map[i] = ( map[i] << 1 ) + 0;
}
}
/** size表示每行允许摆放炮兵的情况数 */
int size = 0;;
/* 对size的数值进行计算,
* 枚举从0 到 1 << m 的所有数,每个数的二进制表示中的1 表示在
* 该处摆放炮兵,0 表示不摆放。
* 摆放遵循的规则是:不允许两个炮兵之间的间距 < 2
*/
for( i = 0; i < ( 1 << m ); i ++ ){
int cc = 0;
int flag = 0;
int ii = i;
while( ii > 0 ){
if( ( ii & 1 ) == 1 ){
if( flag > 0 )
break;
else flag = 2;
cc ++;
}
else flag --;
ii = ii >> 1;
}
if( ii == 0 ){
count[size] = cc;
/** 初始化第一行 */
if( ( map[1] | i ) == map[1] )
f[1][size][0] = cc;
state[size++] = i;
}
}
/** 对行进行循环 */
for( i = 2; i <= n; i ++ )
/** 对上一行的摆放状态进行循环 */
for( int k1 = 0; k1 < size; k1 ++ )
/** 对上两行的摆放状态进行循环 */
for( int k2 = 0; k2 < size; k2 ++ )
/** 若该种上一行和上两行的摆放状态合理 */
if( f[i - 1][k1][k2] > 0 )
/** 对当前行的摆放状态进行循环 */
for( int j = 0; j < size; j ++ )
/* 若当前行的这一摆放状态与前一行和前两行的摆放状态都不冲突
* 且和地形也不冲突,则比较大小后更新
* f[i][j][k1] = f[i - 1][k1][k2] + count[j];
*/
if( ( state[k1] & state[j] ) == 0 && ( state[k2] & state[j] ) == 0 )
if( ( map[i] | state[j] ) == map[i] )
if( f[i][j][k1] < f[i - 1][k1][k2] + count[j] )
f[i][j][k1] = f[i - 1][k1][k2] + count[j];
/** 计算第i 行的各种摆放方式中炮兵数的最大值 */
int max = 0;
for( i = 0; i < size; i ++ ){
for( int j = 0; j < size; j ++ )
if( f[n][i][j] > max )
max = f[n][i][j];
}
printf("%d\n", max );
return 0;
}