woc,优先级真恶心,调了我半天
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int mod=1e8;
int n,m;
int sq[105][12];
int mp[105];
bool judge[105],can[105][105];
int legal[105],sum[105];
long long dp[105][105][105];
//dp[i][s][t],记录当前在第i行当前状态为legal[s],上一行状态为legal[t]
long long ans=0;
char a;
int cnt=0;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>a;
if(a=='P') sq[i][j]=1;
if(a=='H') sq[i][j]=0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
mp[i]=(mp[i]<<1)+sq[i][j];
}//第一步,把地图转化为二进制
for(int s=0;s<(1<<m);s++)
{
if( ((s&(s<<1))==0) && ((s&(s<<2))==0) && ((s&(s>>1))==0) && ((s&(s>>2))==0) )
{
legal[++cnt]=s;//储存合法情况
judge[cnt]=1;
int t=s;
while(t)
{
if(t%2==1) sum[cnt]++;
t=t>>1;
}
}
}//第二步,储存合法状态
for(int i=1;i<=cnt;i++)
{
if( (judge[i]) && ( (legal[i]&mp[1])==legal[i]) )
{
can[1][i]=1;
dp[1][i][0]=sum[i];
}
}//第三步,找出第一行状态的方案数
for(int i=1;i<=cnt;i++)
{
if( (judge[i]) && ( (legal[i]&mp[2])==legal[i]) )
{
can[2][i]=1;
for(int j=1;j<=cnt;j++)
{
if(!can[1][j]) continue;
if((legal[i]&legal[j])==0)
{
dp[2][i][j]=max(dp[2][i][j],dp[1][j][0]+sum[i]);
}
}
}
}//第四步,找出第二行状态的方案数
for(int i=3;i<=n;i++)
{
for(int now=1;now<=cnt;now++)//当前状态
{
if( (judge[now]) && (legal[now]&mp[i])==legal[now] )
{
can[i][now]=1;
for(int s=1;s<=cnt;s++)//上两行状态
{
if(!can[i-2][s]) continue;
if((legal[s]&legal[now])!=0) continue;
for(int t=1;t<=cnt;t++)//上一行状态
{
if(!can[i-1][t]) continue;
if( ((legal[now]&legal[t])!=0) || ((legal[t]&legal[s])!=0) ) continue;
dp[i][now][t]=max(dp[i][now][t],dp[i-1][t][s]+sum[now]);
}
}
}
}
}//第五步,3到n行状压
for(int i=1;i<=cnt;i++)
for(int j=1;j<=cnt;j++)
{
ans=max(ans,dp[n][i][j]);
}//记录答案
printf("%lld\n",ans);
}