0712-动态规划-抢匪的财宝

2.抢匪的财宝

【问题描述】

            古威市长和韩丁纳市长都争着要找到抢匪野蛮老危的地图宝藏,放在自己城市的展览馆里。汪汪队帮助古威市长抢先一步找到了藏宝藏的地方。

            宝藏埋在洞穴中长为n, 宽为m的矩形地面下。汪汪队从洞穴入口A(图中左上角)进入,从洞穴出口B(图中右下角)离开,每步只能向下走或向右走,当走到[x,y]方格时,可取出[x,y]方格及与[x,y]相邻的上下左右四个方向方格中的全部财宝。每个方格中的数表示财宝数量,如下图所示:

汪汪队从图中A[1,1]走到B[5,5]格时:

通过的路径是[1,1]→[2,1]→[3,1]→[4,1]→[4,2]→[4,3]→[4,4]→[4,5]→[5,5]

最多能取到财宝的数量为:0+1+2+1+0+3+0+0+8+5+0+5+0+6+7+0+8+8+6=60

【输入文件】

输入文件treasure.in中有n+1行。

第1行包含2个用空格分开的正整数n、m,分别表示洞穴中埋藏财宝地面的长和宽;接下来的n行,每行m个用空格分隔的正整数,表示各个格子中的财宝数量。

【输出文件】

  输出文件treasure.out中有1个正整数,是汪汪队最多能取到的财宝数量。

【输入输出样例】

treasure.in

treasure.out

5 5

0 1 2 0 5

2 1 3 0 0

0 3 6 8 6

0 0 5 5 7

8 0 0 0 8

60

 

【数据规模】

100%的数据:1≤n,m≤500。

 

又是这样,想到了dp,但不知道怎么状态转移!!!!刷dp的题啊!!!!!

(难过(;′⌒`)下午敲了好久的博客,居然没保存起。。。。但乖巧的宝宝决定重新再写一遍,快夸夸我)

对于每一个点而言,我们都需要获取他自己以及他上下左右四个位置的财宝数量,而每个位置的财宝只允许被取一次,所以如果以前取过该位置了,下次就不能计算了。但我们怎么知道哪些是可选,哪些又不可选呢?这就要考虑上一个点是从上面转移下来,还是从左面了。但上上个点就不影响了吗?错,会影响(具体为什么,可以画画图,我这里就不展示了)那上上上个点呢?哈,就不会影响了。

所以我们用个四维数组来存储我们需要的东西。f[i][j][2][2]-->i,j表示当前位置,第三维记录上一个点是从上面还是左面转移过来,第四维记录上上个点。(0表示上面,1表示左面)

状态转移的话,主要考虑四种状态0,0     0,1      1,1     1,1,看在上一个点的基础上可以增加哪些没有被取过的值。

看看代码的转移方程吧,我会标记出来

还有就是f数组初始化的问题,第一行和第一列单独搞一下

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,m,a[505][505];
int f[505][505][3][3];
int main(){
	scanf("%d%d",&n,&m);
	int i,j,k;
	for(i=1;i<=n;++i)
		for(j=1;j<=m;++j)
			scanf("%d",&a[i][j]);
	
	memset(f,0,sizeof(f));
	
	f[1][1][0][0]=a[1][1]+a[1][2]+a[2][1];
	for(i=2;i<=n;++i)
		f[i][1][0][0]=f[i-1][1][0][0]+a[i+1][1]+a[i][2];
		
	f[1][1][1][1]=a[1][1]+a[1][2]+a[2][1];
	for(i=2;i<=m;++i)
		f[1][i][1][1]=f[1][i-1][1][1]+a[2][i]+a[1][i+1];//F数组的初始化完成!
		
	for(i=2;i<=n;++i)
		for(j=2;j<=m;++j)
		{
			f[i][j][0][0]=max(f[i-1][j][0][0],f[i-1][j][0][1])+a[i+1][j]+a[i][j-1]+a[i][j+1];
			f[i][j][0][1]=max(f[i-1][j][1][0],f[i-1][j][1][1])+a[i][j+1]+a[i+1][j];
			f[i][j][1][0]=max(f[i][j-1][0][0],f[i][j-1][0][1])+a[i][j+1]+a[i+1][j];
			f[i][j][1][1]=max(f[i][j-1][1][0],f[i][j-1][1][1])+a[i+1][j]+a[i-1][j]+a[i][j+1];//四个不同状态的转移
		}
	int ans=max(max(f[n][m][0][0],f[n][m][0][1]),max(f[n][m][1][1],f[n][m][1][0]));

	
	printf("%d",ans);
	
	return 0;
}//F数组的初始化完成!
		
	for(i=2;i<=n;++i)
		for(j=2;j<=m;++j)
		{
			f[i][j][0][0]=max(f[i-1][j][0][0],f[i-1][j][0][1])+a[i+1][j]+a[i][j-1]+a[i][j+1];
			f[i][j][0][1]=max(f[i-1][j][1][0],f[i-1][j][1][1])+a[i][j+1]+a[i+1][j];
			f[i][j][1][0]=max(f[i][j-1][0][0],f[i][j-1][0][1])+a[i][j+1]+a[i+1][j];
			f[i][j][1][1]=max(f[i][j-1][1][0],f[i][j-1][1][1])+a[i+1][j]+a[i-1][j]+a[i][j+1];//四个不同状态的转移
		}
	int ans=max(max(f[n][m][0][0],f[n][m][0][1]),max(f[n][m][1][1],f[n][m][1][0]));

	
	printf("%d",ans);
	
	return 0;
}

我还是有数据~

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值