Description
![](https://i-blog.csdnimg.cn/blog_migrate/ba1d4fa736b99550a7ee43784c287df9.jpeg)
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
Input
接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。
Output
Sample Input
5 4 PHPP PPHH PPPP PHPP PHHP
Sample Output
6
//
#include <iostream>
#include<cstdio>
using namespace std;
const int Max = 61;
int dp[101][Max][Max], num[Max], sum[Max],len = 0;
//f[i][j][k]表示第i行状态为num[j],第i-1行状态为num[k]的最大炮兵数,
//num[i]表示第i个状态对应的10进制数,sum[i]表示第i个状态有多少个1,len:有多少个状态
int n,m;
char a[101][11];
void build() //预处理
{
len=0;
for(int i=0;i<(1<<m);i++)
{
int tmp=i;
if(((tmp<<1)&i)||((tmp<<2)&i)) continue;
num[++len]=i;
sum[len]=(tmp&1);
while(tmp=(tmp>>1)) sum[len]+=(tmp&1);
}
}
bool match(int x, int y)//x表示一行地形代表的10进制数,y是状态对应的10进制数。判断y是否合法
{
if(x&y) return 0;
return 1;
}
int main()
{
while(scanf("%d%d",&n,&m) == 2)
{
build();
for(int i = 1; i <= n; i++) scanf("%s",&a[i]);
int num2[101] = {0};//地形每一行对应的10进制数
for(int i = 1; i <= n; i++)
for(int j = 0; j < m; j++)
if(a[i][j] == 'H') num2[i] += (1 << j);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= len; j++)
for(int k = 1; k <= len; k++)
dp[i][j][k] = 0;
for(int i = 1; i <= len; i++)//初始化第一行
{
if(match(num2[1],num[i]))
{
for(int j = 1; j <= len; j++)
dp[1][i][j] = sum[i];
}
}
for(int j = 1; j <= len; j++)//初始化第二行
{
if(match(num2[2],num[j]))
{
for(int k = 1; k <= len; k++)
{
if((num[j] & num[k]) == 0){//判断上下2行会不会相互攻击
for(int l = 1; l <= len; l++)
{
if(dp[1][k][l] + sum[j] > dp[2][j][k])
dp[2][j][k] = dp[1][k][l] + sum[j];
}
}
}
}
}
for(int i = 3; i <= n; i++)//根据方程DP
{
for(int j = 1; j <= len; j++)
{
if(match(num2[i], num[j]))
{
for(int k = 1; k <= len; k++)
{
for(int l = 1; l <= len; l++)
{
if((num[j] & num[k]) == 0 && (num[j] & num[l]) == 0 && (num[k] & num[l]) == 0 && dp[i-1][k][l] + sum[j] > dp[i][j][k])
dp[i][j][k] = dp[i-1][k][l] + sum[j];
}
}
}
}
}
int ans = 0;
for(int i = 1; i <= len; i++)//求结果
for(int j = 1; j <= len; j++)
if(dp[n][i][j] > ans)
ans = dp[n][i][j];
printf("%d\n",ans);
}
return(0);
}