习题:Maja(dp,滚动数组)

题目:

Maja和蜜蜂在一片神奇的草地上为花授粉,这块草地可以表示为一个n行m列的矩形,在第i行第j列中有CIJ朵没有授粉的花。

Maja的蜂巢位于第a行第b列,她将从她的蜂巢开始为这些花授粉,去草地上的某些块授粉,然后再返回她的蜂巢。每次操作,Maja可以向相邻的上下左右中的一个方格移动,而且她永远不会离开草地。每次她经过的某块草地,都会给这块草地上所有未授粉的花授粉。但草地很神奇,一旦Maja离开草地(i,j),所有授粉的花都会消失,新的未授粉的花又会在这片土地上生长。

由于Maja不可能永远飞行,她会在飞过k个格子后感到疲倦,并乐意向她的蜜蜂朋友们讲述她的冒险故事。请问,在Maja授粉并在k步后返回蜂巢,她能授粉的花的数量是多少?

输入格式

第一行包含正整数n,m(2≤n,m≤100),a(1≤a≤n),b(1≤b≤m)和k(2≤k≤1000000000),题目保证k是偶数

接下来n行,每行输入m个数字,表示第i行第j列有未授粉的花Cij(0≤Cij≤1000000000)朵。

题目保证在蜂巢的位置不会有任何花。

输出格式

输出一个数,表示Maja最多能授粉的花的数量。

样例

样例输入1

2 2 1 1 2
0 1
2 10

样例输出1

2

样例输入2

2 2 1 1 4
0 5
5 10

样例输出2

20

样例输入3

3 3 2 2 6
5 1 0
1 0 3
1 3 3

样例输出3

15

思路:
最初始的DP很容易想,即dp[i][j][k]表示在k时间,从(a,b)走到(i,j)的最大值

但是我们发现dp的转移方程其实只跟k-1有关,也就是说k我们可以滚动

之后,我们知道路径中的一段一定是在两个点之间反复横跳,

也就是说最外层枚举的时间其实只用到min(k,n*m),因为路径最长就n*m

代码:
 

# include<bits/stdc++.h>
using namespace std;
long long f[105][105][2],c[105][105];
long long n,m,A,B,K,ans=-0x7f7f7f7f7fll;
long long get(long long a,long long b,long long c,long long d)
{
	if(b>a)
		a=b;
	if(c>a)
		a=c;
	if(d>a)
		a=d;
	return a;
}
int main()
{
	cin>>n>>m>>A>>B>>K;
	K=K>>1;
	for(int i=0;i<=n+1;i++)
		for(int j=0;j<=m+1;j++)
			c[i][j]=f[i][j][0]=f[i][j][1]=-0x7f7f7f7f7fll;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>c[i][j];
		}
	}
	f[A][B][0]=0;
	for(long long r=1;r<=min(K,n*m);r++)
	{
		long long now=r&1;
		long long pst=now^1;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
			{
				long long temp=get(f[i-1][j][pst],f[i+1][j][pst],f[i][j-1][pst],f[i][j+1][pst]);
				f[i][j][now]=max(temp+c[i][j],-0x7f7f7f7f7fll);
				if (f[i][j][now]<0)
					 continue;
				long long d=f[i][j][now]+temp;
				d+=(K-r)*(c[i][j]+get(c[i-1][j],c[i+1][j],c[i][j-1],c[i][j+1]));
				ans=max(ans,d);
			}
	}
	cout<<ans;
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值