Autonomier @ 2020-03-25 19:24:59
#include<bits/stdc++.h>
//用了状态压缩的思想,但只过了第一个和第三个测试点,其他都是WrongAnswer
using namespace std;
#define ll long long
#define maxn 10000000
inline int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
int n,m,res,dp[1000][1000][3],a[20],sum[1<<10+5];
//dp[i][j][k]表示前一行状态为sta[i],当前行状态为sta[j],k=当前行数%3(因为开三维数组会炸空间)
int sta[1<<10+5];//存储可行状态
char knd;
inline int cal(int x)
//统计每个二进制数中有几个一,就是放了几个兵
{
int cnt=0;
while(x)
{
if(x&1)
cnt++;
x>>=1;
// cout<<7;
}
return cnt;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
//存储地图,平原为1,山地为0
{
cin>>knd;
a[i]<<=1;
a[i]+=(knd=='P' ? 1:0);
}
}
int k=0;
for(int i=0;i<(1<<m);i++)
//只考虑一行内的所有可行情况
{
if(!(i&(i<<1))&&!(i&(i<<2))&&!(i&(i>>2))&&!(i&(i>>1)))
{
sum[++k]=cal(i);
sta[k]=i;
}
}
for(int i=1;i<=k;i++)
//将dp数组第一行更新
{
if((sta[i]&a[1])==sta[i])
{
dp[0][i][1]=sum[i];
}
}
for(int j=1;j<=k;j++)
{
for(int i=1;i<=k;i++)
//更新第二行
{
if(((a[1]&sta[i])==sta[i])&&((a[2]&sta[j])==sta[j])&& !(sta[i]&sta[j]))
{
dp[i][j][2]=sum[i]+sum[j];
}
}
}
for(int i=3;i<=n;i++)
//从第三行开,进行dp
{
for(int j=1;j<=k;j++)//枚举上上行状态
{
for(int l=1;l<=k;l++)//枚举上一行状态
{
for(int e=1;e<=k;e++)//枚举当前行状态
{
if(((sta[j]&a[i-2])==sta[j])&&((sta[l]&a[i-1])==sta[l])&&((sta[e]&a[i])==sta[e])&& !(sta[j]&sta[l])&& !(sta[l]&sta[e])&& !(sta[j]&sta[e]))
//分别判断是否与地图相符,且上下行是否有冲突
{
dp[l][e][i%3]=max(dp[l][e][i%3],dp[j][l][(i-1)%3]+sum[e]);
}
}
}
}
}
for(int i=1;i<=k;i++)
{
for(int j=1;j<=k;j++)
{
if(!(sta[i]&sta[j]))
{
res=max(res,dp[i][j][n%3]);//统计第n行答案,寻找最大值
}
}
}
cout<<res<<endl;
return 0;
}
by derta @ 2020-04-24 23:04:12
铜球