一开始我只开了二维数组来存储状态,怎么都想不出
后来百度了一下,才知道正解
按层数来dp,如果用dp[i][j][k]来表示在第i行,状态为j,i-1行状态为k时的状态,那么有转移方程f[i][j][k]=max(f[i][j][k],f[i-1][k][l]+bit[i]);
枚举i(层数),j(当前层状态),k(上一层状态),l(上上层状态)就可以来进行转移了。
然而,由于有最多1024种状态,真正可行的只有大概70种,所以必须先预处理出来存着,这样状态数组f也可以省下空间。
(上面预处理步骤不可偷懒,否则TLE/MLE)
地图的每一层也可以变为一个二进制数,在判断可行性时更方便,但是我太懒了没有写。
上代码:
#include<bits/stdc++.h>
#define RI register int
using namespace std;
int n,m,l,cnt,ans;
int bit[1<<11],f[110][70][70],sta[70];
char mp[110][12];
inline bool ok1(int x,int v)
{
for (RI i=1;i<=m;i++) if (mp[x][i]!='P'&&((sta[v]>>(i-1))&1)) return 0;
return 1;
}
inline bool ok2(int x,int y){return !(sta[x]&sta[y]);}
inline bool ok3(int x)
{
int a=(x>>1),b=(x>>2);
if ((a&x)||(b&x)) return 0;
return 1;
}
int num(int x)
{
int ret=0;
while (x) x-=(x&-x),ret++;
return ret;
}
void in()
{
scanf("%d %d",&n,&m);
for (RI i=1;i<=n;i++)
for (RI j=1;j<=m;j++)
cin>>mp[i][j];
return;
}
void pre()
{
l=(1<<m)-1;
for (RI i=0;i<=l;i++)
if (ok3(i))
{
sta[++cnt]=i;
bit[cnt]=num(i);
}
for (RI i=1;i<=cnt;i++) if (ok1(1,i))
{
f[1][i][0]=bit[i];
ans=max(ans,bit[i]);
}
if (n==1) return;
for (RI i=1;i<=cnt;i++) if (ok1(2,i))
{
for (RI j=1;j<=cnt;j++) if (ok1(1,j)&&ok2(i,j))
{
f[2][i][j]=max(f[2][i][j],f[1][j][0]+bit[i]);
ans=max(ans,f[2][i][j]);
}
}
return;
}
void solve()
{
for (RI i=3;i<=n;i++)
for (RI j=1;j<=cnt;j++)
if (ok1(i,j))
for (RI k=1;k<=cnt;k++)
if (ok1(i-1,k)&&ok2(j,k))
for (RI r=1;r<=cnt;r++)
if (ok1(i-2,r)&&ok2(j,r)&&ok2(k,r)){
f[i][j][k]=max(f[i][j][k],f[i-1][k][r]+bit[j]);
ans=max(ans,f[i][j][k]);
}
printf("%d",ans);
return;
}
int main()
{
in();
pre();
solve();
return 0;
}