中文题意不解释,由于一行最多10位也就是一行中所有状态只有1000+,并且根据题目描述每一个炮的周围左右两位是不能放第二个的,所以我们可以再缩小状态数量,最后大约60+。炮的上下也是不能放第二个炮的所以我们可以知道,当前的状态会与之前两个状态有关,由于我们缩小了可用状态的数量我们可以对于每一行,枚举当前行和前两行的状态,根据状态的相关性我们可以得到状态转移方程。dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k]+num[j]])。num为该状态下,炮的数量。num数组提前打个表就行。
补充一句,改题用二维数组是不行的,状态关联层数太多,二维数组会多包涵状态。(但是题中给的数据能过~~~)
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#define INF 0x3f3f3f3f
#define mod 100000000
using namespace std;
int mp[120];
int dp[101][70][70];
int n,m;
int main()
{
int num[70],vnum[70],d,p=0;
memset(num,0,sizeof(num));
memset(dp,0,sizeof(dp));
memset(mp,0,sizeof(mp));
memset(vnum,0,sizeof(vnum));
char c;
scanf("%d%d",&n,&m);
for(int i=0;i<=(1<<m)-1;i++)
{
int x=i;
if(!(i&i<<1)&&!(i&i<<2))
{
vnum[p]=i;
while(x)
{
if(x%2==1) num[p]++;
x/=2;
}
p++;
}
}
for(int i=1;i<=n;i++)
{
getchar();
for(int j=0;j<m;j++)
{
scanf("%c",&c);
mp[i]<<=1;
if(c=='H') mp[i]=mp[i]+1;
}
}
for(int i=0;i<p;i++)
{
if(!(vnum[i]&mp[1]))
dp[1][i][0]=num[i];
}
int i,j,k,l;
for(i=2;i<=n;++i)
{
for(j=0;j<p;++j)
{
if(!(vnum[j]&mp[i]))
{
if(!(vnum[j]&vnum[j]<<1))
{
if(!(vnum[j]&vnum[j]<<2)){
for(k=0;k<p;++k)
{
if(!(vnum[k]&mp[i-1]))
{
if(!(vnum[j]&vnum[k]))
{
for(l=0;l<p;++l)
{
if(!(vnum[l]&mp[i-2])){
if(!(vnum[j]&vnum[l]))
{
if(!(vnum[l]&vnum[k])){
//d=dp[i-2][l]+num[k];
dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+num[j]);
}
}
}
}
}
}
}
}
}
}
}
}
int maxx=0;
for(i=0;i<p;i++)
{
for(j=0;j<p;j++)
{
if(maxx<dp[n][i][j])
maxx=dp[n][i][j];
}
}
printf("%d\n",maxx);
return 0;
}