题意
中文题。
题解
首先考虑每一行(横向)的影响,每个战队战火波及范围是两格,所以保证(state & state<<1)和(state & state<<2)都要为0。
并且每行中最多的状态不是1<<10,正因为战火会影响两格,所以一行的状态最多不超过60。所以可以预处理出每行可行的状态。
再考虑列的情况,第i行只会影响到第i-1行和i-2行的同一列,要保证state(cur) & state(pre) & state(prepre) 都为0。
状态转移方程是dp[i][curst][pre]=max{dp[i-1][prest][prepre]},dp[cur][pre]表示当前行相对于前一行的最大战队数。
代码
#include<cstdio>
#include<algorithm>
#include<string.h>
#include <string.h>
#include <math.h>
using namespace std;
typedef long long ll;
int dp[105][60][60];
char M[105][12];
bool is[105][12];
int can[150];
const int Mod = 1e8;
int n, m, t = 0;
void init()
{
for(int i = 0; i < (1<<10); i++)
{
if((i&(i<<1)) || (i&(i<<2))) continue; //一行中相邻的战队不会攻击
can[++t] = i;
}
return;
}
int check(int x, int state) //看此行state是否为符合题意的状态
{
int cnt = 0;
if( state >= (1<<m) ) return -1;
for(int i = 1; i <= m; i++)
{
if( (1<<(i-1))& state ) cnt++;
if(!is[x][i]) //x行第i个是山地则state(m-i)位不能放战队
{
if( (1<<(m-i)) & state) return -1;
}
}
return cnt;
}
int main()
{
while(scanf("%d%d", &n, &m) != EOF)
{
init();
for(int i = 1; i <= n; i++)
{
scanf("%s", M[i]+1);
for(int j = 1; j <= m; j++)
{
if(M[i][j] == 'P') is[i][j] = 1;
else is[i][j] = 0;
}
}
int ans = 0, now;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= t; j++)
{
int cnt = check(i, can[j]);
if(cnt!=-1) {
for(int k = 1; k <= t; k++)
{
now = 0;
if(!(can[k] & can[j])) { //与i-1行比较
dp[i][can[j]][can[k]] = cnt;
for(int q = 1; q <= t; q++)
{
if(i > 1) {
if(!(can[j]&can[q])) //与i-2行比较
now = max(now, dp[i-1][can[k]][can[q]]);
}
}
}
dp[i][can[j]][can[k]] += now;
if(i == n) ans = max(ans, dp[i][can[j]][can[k]]);
}
}
}
}
printf("%d\n",ans);
}
return 0;
}