给出一个H的行和W列的网格。第i行第j列的状态是由一个字母的A[i][j]表示,如下:
“.” 此格为空。
“o” 此格包含一个机器人。
“E” 此格包含一个出口,保证出口在整个网格中有且只有一个
每次可以选择上,下,左,右之一的方向,将所有剩余的机器人向这个方向移动一个格子,如果一个机器人被移出了网格,那么这个机器人会爆炸,并立即消失。如果一个机器人移动到出口所在的格子,机器人将获救,并消失,最多有多少机器人获救。
这道题目的DP是真的没有看出来。
只能打了个60分的暴力。
我们可以用E往上下左右走,然后在相反方向的一行就会多一行的禁止区域。
因为要牺牲一行的机器人,所以扩展出来的一行机器人一定要全部都拿走。
那么我们设 f[l][r][u][d] 表示E向左右上下走的最远距离,
然后每次DP可以把l,r,u,d分别都+1来转移,然后把可以得到的机器人加起来(但是可能当前这个状态要得到的机器人已经是被禁止掉的,所以要判断边界)
时间复杂度 O((nm)22)
这样空间是会爆的,所以要拿一个出来滚动。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=107;
int i,j,k,l,t,n,m,ans,sx,sy,r,u,d,z;
int yi,er,yi1,er1;
int f[2][maxn][maxn][maxn],bz[maxn][maxn];
int lie[maxn][maxn],hang[maxn][maxn];
char s[maxn][maxn];
int main(){
// freopen("fan.in","r",stdin);
scanf("%d%d",&n,&m);
fo(i,1,n){
scanf("%s",s[i]+1);
fo(j,1,m){
if(s[i][j]=='E')sx=i,sy=j;
if(s[i][j]=='o')bz[i][j]=1;
}
}
fo(i,1,n)fo(j,1,m)hang[i][j]=hang[i][j-1]+bz[i][j];
fo(j,1,m)fo(i,1,n)lie[j][i]=lie[j][i-1]+bz[i][j];
fo(i,0,sy-1){
l=1-l;
memset(f[1-l],0,sizeof(f[1-l]));
fo(r,0,m-sy){
fo(u,0,sx-1){
fo(d,0,n-sx){
ans=max(ans,f[l][r][u][d]);
if(i+r
else f[1-l][r][u][d]=max(f[1-l][r][u][d],f[l][r][u][d]);
if(i+r<(m-sy))f[l][r+1][u][d]=max(f[l][r+1][u][d],f[l][r][u][d]+lie[sy+r+1][min(n-u,sx+d)]-lie[sy+r+1][max(d,sx-u-1)]);
else f[l][r+1][u][d]=max(f[l][r+1][u][d],f[l][r][u][d]);
if(u+d
else f[l][r][u+1][d]=max(f[l][r][u+1][d],f[l][r][u][d]);
if(n-u>d+sx)f[l][r][u][d+1]=max(f[l][r][u][d+1],f[l][r][u][d]+hang[d+sx+1][min(sy+r,m-i)]-hang[d+sx+1][max(r,sy-i-1)]);
else f[l][r][u][d+1]=max(f[l][r][u][d+1],f[l][r][u][d]);
}
}
}
}
printf("%d\n",ans);
}