传送门
这个题只要想到移动机器人和移动出口是等价的就好做了
考虑设\(f[i][j][k][t]\)为最远向左移动\(i\),向右移动\(j\),向上移动\(k\),向下移动\(t\),这个矩形内最多能救的机器人
转移就记录一个前缀和来辅助转移,这样复杂度就在能通过的范围内了
但是转移还是比较麻烦的,还需要考虑当前状态下哪些机器人是已经死了的
空间有点卡,可以选择开short也可以将第一维滚动
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
using namespace std;
void read(int &x){
char ch;bool ok;
for(ok=0,ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1;
for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());if(ok)x=-x;
}
#define rg register
const int maxn=110;
#define max(a,b) ((a)>(b)?(a):(b))
short ans,f[maxn][maxn][maxn][maxn],l[maxn][maxn],r[maxn][maxn];
int n,m,x,y;char s[maxn];
void solve(){
int le=y-1,rt=m-y,up=x-1,dw=n-x;
for(rg int i=0;i<=le;i++)
for(rg int j=0;j<=rt;j++)
for(rg int k=0;k<=up;k++)
for(rg int t=0;t<=dw;t++){
if(y-i-1>j){
int now1=max(x-k,t+1),now2=min(x+t,n-k);
f[i+1][j][k][t]=max(f[i+1][j][k][t],f[i][j][k][t]+r[now2][y-i-1]-r[now1-1][y-i-1]);
}
else f[i+1][j][k][t]=max(f[i+1][j][k][t],f[i][j][k][t]);
if(y+j+1+i<=m){
int now1=max(x-k,t+1),now2=min(x+t,n-k);
f[i][j+1][k][t]=max(f[i][j+1][k][t],f[i][j][k][t]+r[now2][y+j+1]-r[now1-1][y+j+1]);
}
else f[i][j+1][k][t]=max(f[i][j+1][k][t],f[i][j][k][t]);
if(x-k-1>t){
int now1=max(y-i,j+1),now2=min(y+j,m-i);
f[i][j][k+1][t]=max(f[i][j][k+1][t],f[i][j][k][t]+l[x-k-1][now2]-l[x-k-1][now1-1]);
}
else f[i][j][k+1][t]=max(f[i][j][k+1][t],f[i][j][k][t]);
if(x+t+1+k<=n){
int now1=max(y-i,j+1),now2=min(y+j,m-i);
f[i][j][k][t+1]=max(f[i][j][k][t+1],f[i][j][k][t]+l[x+t+1][now2]-l[x+t+1][now1-1]);
}
else f[i][j][k][t+1]=max(f[i][j][k][t+1],f[i][j][k][t]);
}
printf("%d\n",f[le][rt][up][dw]);
}
int main(){
read(n),read(m);
for(rg int i=1;i<=n;i++){
scanf("%s",s+1);
for(rg int j=1;j<=m;j++){
if(s[j]=='E')x=i,y=j;
else if(s[j]=='o')l[i][j]=r[i][j]=1;
}
}
for(rg int i=1;i<=n;i++)
for(rg int j=1;j<=m;j++)
l[i][j]+=l[i][j-1];
for(rg int i=1;i<=m;i++)
for(rg int j=1;j<=n;j++)
r[j][i]+=r[j-1][i];
solve();
}