洛谷 P7074 [CSP-J2020 T4] 方格取数 动态规划dp

48 篇文章 0 订阅
17 篇文章 0 订阅

题目描述

设有n×m的方格图,每个方格中都有一个整数。现有一只小熊,想从图的左上角走到右下角,每一步只能向上、向下或向右走一格,并且不能重复经过已经走过的方格,也不能走出边界。小熊会取走所有经过的方格中的整数,求它能取到的整数之和的最大值。

输入

输入文件名为 number.in。

第 1 行两个正整数n,m。

接下来n行每行m个整数,依次代表每个方格中的整数。

输出

输入文件名为 number.out。

一个整数,表示小熊能取到的整数之和的最大值

样例输入1
3 4
1 -1 3 2
2 -1 4 -1
-2 2 -3 -1
样例输出1
9

提示/说明

【样例1解释】

按上述走法,取到的数之和为 1 + 2 + (-1) + 4 + 3 + 2 + (-1) + (-1) = 9,可以证明为最大值。
 


注意,上述走法是错误的,因为第 2 行第 2 列的方格走过了两次,而根据题意,不能重复经过已经走过的方格。

另外,上述走法也是错误的,因为没有走到右下角的终点。
【样例2解释】

按上述走法,取到的数之和为(-1) + (-1) + (-3) + (-2) + (-1) + (-2) = -10,可以证明为最大值。因此,请注意,取到的数之和的最大值也可能是负数。
【样例 3】

见选手目录下的 number/number3.in 与 number/number3.ans。

【数据范围与提示】

对于 20% 的数据,n,m≤ 5。

对于40% 的数据,n,m≤ 50。

对于 70% 的数据,n,m≤ 300。

对于 100% 的数据,1 ≤n,m≤ 1000。方格中整数的绝对值不超过 10^4。

 这题刚一看:不就是个普通的dp吗

自信写代码ing

诶,这怎么还带往上走的?

😓😓😓😓

这题与经典dp差别就在这里

根据dp的无后效性,不能往上走又往下走

思路:

一次dp不行,那就两次(

定义f数组时发生变化

之前的二维不得不提升维度变成三维(蒟蒻目前想不出这题的二维AC方法)

第三维:

f[i][j][0]表示从上面那个点或者右边的点过来的最大值

 画个丑图~

f[i][j][0]=max(f[i-1][j][0],max(f[i][j-1][0],f[i][j-1][1]))+a[i][j];

(因为无有效性,如果这个点是从上面的点过来的话,那么上面的点的第三维也得是0,下面同理)

很好理解 

f[i][j][1]代表从右边或者下边过来的最大值

    f[i][j][1]=max(f[i+1][j][1],max(f[i][j-1][0],f[i][j-1][1]))+a[i][j];

初始化 !!!

这题的初始化不能小看,也很特殊

首先先要memset一下毋庸置疑

可是把f数组弄成几呢

0x3f?

-1?

0?

nononononononono

因为代码中有max,如果弄成无限大,那就乱了

所以得定义成无限小:0xcf

然后f[1][0][0]=0  因为我们目前不知道f[1][0][1]是什么,毕竟后面会计算,所以不能初始化f[1][0][1]

上AC代码了~

# include <iostream>
# include <cstdio>
# include <cstring> 
using namespace std;
# define int long long
# define N 1005
int n,m;
int a[N][N],f[N][N][2];
signed main(){
	scanf("%lld%lld",&n,&m);
	for (int i=1;i<=n;i++){
		for (int j=1;j<=m;j++){
			scanf("%lld",&a[i][j]);
		}
	}
	memset(f,0xcf,sizeof(f));
	f[1][0][0]=0;
	for (int j=1;j<=m;j++){//因为上下走是按列的,所以外层循环是j
		for (int i=1;i<=n;i++){
			f[i][j][0]=max(f[i-1][j][0],max(f[i][j-1][0],f[i][j-1][1]))+a[i][j];
		}
		for (int i=n;i;i--){
			f[i][j][1]=max(f[i+1][j][1],max(f[i][j-1][0],f[i][j-1][1]))+a[i][j];
		}
	}
	printf("%lld",f[n][m][0]);//因为右下角的点不能从下面走来,所以得输出上面走来的
	return 0;
}

 AC记录

 

制作不易,点个赞吧~

感谢你看到了最后

这是我第一年(完整的一年)学编程

也是我度过的第一个1024节

点个赞再走吧~

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值