思路:首先做個預處理,把每一行可以放的狀態存起來,以後就可以只看這麼多狀態而不是for全看一遍了。
之後,因爲放一個可以影響四個方向2格,所以第i行的狀態和i-1行i-2行有關係的,通過之前的狀態來推,狀態轉移方程可以寫爲:
dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+f[i][j])
這裏i代表第i行,j爲第i行的狀態,k爲第i-1行狀態,l爲i-2行狀態,f[i][j]表示第i行在j狀態下放的個數。
記得前兩行特殊處理下。
這裏直接開數組會MLE,所以用滾動數組來。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<string>
#include<algorithm>
#include<queue>
using namespace std;
char a[111][15];
int f[111][1025];
int dp[3][1025][1025];
int m,n;
vector<int>g[111];
void pre()
{
int l=(1<<m);
for(int i=0;i<n;i++)
{
for(int j=0;j<l;j++)
{
int cnt=-1;
int r=j;
bool flag=0;
int num=0;
for(int k=0;k<=m;k++)
{
if(r%2)
{
if(cnt!=-1&&cnt<2)
{
flag=1;
break;
}
if(a[i][k]=='H')
{
flag=1;
break;
}
num++;
cnt=0;
}
else if(cnt!=-1)cnt++;
r/=2;
}
if(flag==0)
{
g[i].push_back(j);
f[i][j]=num;
}
}
}
}
void solve()
{
if(n==1)
{
int ans=0;
for(int i=0;i<g[0].size();i++)ans=max(ans,f[0][g[0][i]]);
printf("%d\n",ans);
}
else
{
int ans=0;
memset(dp,0,sizeof(dp));
int x=g[0].size();
int y=g[1].size();
int z;
for(int i=0;i<x;i++)
{
for(int j=0;j<y;j++)
{
if((g[0][i]&g[1][j])==0)
{
dp[0][g[1][j]][g[0][i]]=max(dp[0][g[1][j]][g[0][i]],f[0][g[0][i]]+f[1][g[1][j]]);
ans=max(ans,dp[0][g[1][j]][g[0][i]]);
}
}
}
for(int i=2;i<n;i++)
{
x=g[i].size();
y=g[i-1].size();
z=g[i-2].size();
for(int j=0;j<x;j++)
{
for(int k=0;k<y;k++)
{
if(g[i][j]&g[i-1][k])continue;
for(int l=0;l<z;l++)
{
if(g[i][j]&g[i-2][l])continue;
if(g[i-1][k]&g[i-2][l])continue;
dp[1][g[i][j]][g[i-1][k]]=max(dp[1][g[i][j]][g[i-1][k]],dp[0][g[i-1][k]][g[i-2][l]]+f[i][g[i][j]]);
ans=max(ans,dp[1][g[i][j]][g[i-1][k]]);
}
}
}
for(int j=0;j<x;j++)
{
for(int k=0;k<y;k++)
{
dp[0][g[i][j]][g[i-1][k]]=dp[1][g[i][j]][g[i-1][k]];
}
}
memset(dp[1],0,sizeof(dp[1]));
}
printf("%d\n",ans);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)scanf("%s",a[i]);
pre();
solve();
return 0;
}