前言
本题的关键是想到让出口和矩形动,而不是机器人动,只要记录出口的位移矩形,便可以知道哪个区域的机器人已经飞出去了。
题目大意
一个网格图,有若干机器人,还有一个出口。
操作一系列指令让机器人上下左右,走出矩形就死,进入出口则得救。
最多救多少机器人?
DP
不妨认为矩形和出口会动。
我们设f[u,d,l,r]表示出口移动的上下左右,然后转移也很容易。
第一维可以省略,若如此做记得最后再执行往上的转移。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100+10;
int f[maxn][maxn][maxn],sum[maxn][maxn];
int i,j,k,l,r,u,d,t,n,m,ex,ey,ans,up,down,left,right;
char ch;
char get(){
char ch=getchar();
while (ch!='.'&&ch!='o'&&ch!='E') ch=getchar();
return ch;
}
int getsum(int a,int b,int x,int y){
return sum[x][y]-sum[a-1][y]-sum[x][b-1]+sum[a-1][b-1];
}
int main(){
scanf("%d%d",&n,&m);
fo(i,1,n)
fo(j,1,m){
ch=get();
if (ch=='E'){
ex=i;
ey=j;
}
else if (ch=='o') sum[i][j]++;
}
fo(i,1,n)
fo(j,1,m)
sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
fo(i,0,n)
fo(j,0,m)
fo(k,0,m)
f[i][j][k]=-100000000;
f[0][0][0]=0;
fo(u,0,n){
if (ex-u<1) break;
fo(d,0,n){
if (ex+d>n) break;
up=max(ex-u,1+d);
down=min(ex+d,n-u);
if (up>down) continue;
fo(l,0,m){
if (ey-l<1) break;
fo(r,0,m){
if (ey+r>m) break;
left=max(ey-l,1+r);
right=min(ey+r,m-l);
if (left>right) continue;
ans=max(ans,f[d][l][r]);
if (u+d<n-ex) f[d+1][l][r]=max(f[d+1][l][r],f[d][l][r]+getsum(ex+d+1,left,ex+d+1,right));
if (l+r<ey-1) f[d][l+1][r]=max(f[d][l+1][r],f[d][l][r]+getsum(up,ey-l-1,down,ey-l-1));
if (l+r<m-ey) f[d][l][r+1]=max(f[d][l][r+1],f[d][l][r]+getsum(up,ey+r+1,down,ey+r+1));
if (u+d<ex-1) f[d][l][r]=max(f[d][l][r],f[d][l][r]+getsum(ex-u-1,left,ex-u-1,right));
}
}
}
}
printf("%d\n",ans);
}