【AGC004E】Salvage Robots【动态规划dp】

貌似我的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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值