貌似我的dp和大多数写法不太一样。。常数巨大。
我们设
f
[
i
]
[
j
]
[
k
]
[
l
]
f[i][j][k][l]
f[i][j][k][l]为剩下横坐标范围为
i
t
o
j
i\ to\ j
i to j,纵坐标范围为
k
t
o
l
k\ to\ l
k to l这个矩形,内部的机器人都还存在,这个矩形外部取出的机器人的最大数量。
转移推一下就好了。反正我开始的时候推错了一些地方,但是状态表示一直没改。
dp的时候可以滚动数组优化空间。时间复杂度
O
(
n
4
)
O(n^4)
O(n4)。这个dp1s跑了
1
0
8
10^8
108,太神奇了。
还有转移其实挺对称和相似的,可以复制代码233
代码
#include<cstdio>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define calc(xl,xr,yl,yr) (sum[xr][yr]-sum[xl-1][yr]-sum[xr][yl-1]+sum[xl-1][yl-1])
const int N=105;
int n,m,ex,ey,ans,sum[N][N],f[2][N][N][N];
char s[N][N];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",s[i]+1);
for(int j=1;j<=m;j++){
sum[i][j]=sum[i][j-1];
if(s[i][j]=='E'){
ex=i;
ey=j;
}else if(s[i][j]=='o'){
sum[i][j]++;
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
sum[i][j]+=sum[i-1][j];
}
}
int sta=0;
for(int i=1;i<=n;i++,sta^=1){
for(int j=n;j>=i;j--){
for(int k=1;k<=m;k++){
for(int l=m;l>=k;l--){
if(i-1>=1&&((i-1<=ex&&j+ex-(i-1)<=n)||(i-1>=ex&&j-((i-1)-ex)>=1))){
f[sta][j][k][l]=max(f[sta][j][k][l],f[sta^1][j][k][l]+calc(i-1,i-1,max(k,ey-(m-l)),min(l,ey+k-1)));
}
if(j+1<=n&&((j+1<=ex&&i+ex-(j+1)<=n)||(j+1>=ex&&i-((j+1)-ex)>=1))){
f[sta][j][k][l]=max(f[sta][j][k][l],f[sta][j+1][k][l]+calc(j+1,j+1,max(k,ey-(m-l)),min(l,ey+k-1)));
}
if(k-1>=1&&((k-1<=ey&&l+ey-(k-1)<=m)||(k-1>=ey&&l-((k-1)-ey)>=1))){
f[sta][j][k][l]=max(f[sta][j][k][l],f[sta][j][k-1][l]+calc(max(i,ex-(n-j)),min(j,ex+i-1),k-1,k-1));
}
if(l+1<=m&&((l+1<=ey&&k+ey-(l+1)<=m)||(l+1>=ey&&k-((l+1)-ey)>=1))){
f[sta][j][k][l]=max(f[sta][j][k][l],f[sta][j][k][l+1]+calc(max(i,ex-(n-j)),min(j,ex+i-1),l+1,l+1));
}
if(i==j&&k==l){
ans=max(ans,f[sta][j][k][l]+(s[i][k]=='o'));
}
}
}
}
}
printf("%d\n",ans);
return 0;
}