洛谷多维DP(1):P1508 Likecloud-吃、吃、吃——有效数字的判断处理

在这里插入图片描述

输入输出样例
输入 #1复制
6 7
16 4 3 12 6 0 3
4 -5 6 7 0 0 2
6 0 -1 -2 3 6 8
5 3 4 0 0 -2 7
-1 7 4 0 7 -5 6
0 -1 3 4 12 4 2
输出 #1复制
41

总结目录

1.状态方程的获取
2.有效数字的判断以及初始化

1 状态方程的获取

我们知道最终是获得最上面的时候的最大能量值,从下面开始吃起。容易想到dp[i][j]表示到达[i,j]能够获得的最大的能量值。由于每次步进只能向上,向右上,向左上,因此比较的时候只需比较

dp[i][j]=max{ dp[i+1][j-1]+a[i][j],dp[i+1][j]+a[i][j], dp[i+1][j+1]+a[i][j] };
状态方程还是比较简单的。

2 有效数字的判断与初始化

这题比较难的是如何判断哪些路径是可以去的,是有效的,让他们参与后续的迭代,而不能去的路径是无效的。

这里我将第0列,第n+1列和第m+1行进行初始化为int_min,即看作是负无穷,显然是合理的,因为无法探索到这个边界,任意值加上这些边界上的值仍然是负无穷。特别的,初始位置[m+1,(n+1)/2]要置0.

但是单纯这样计算会有一个问题,比如如果是负数加上了int_min就会溢出,除此之外,如果原本就是int_min,再加上int_min也是会溢出的。为了处理这样的溢出,我们进行了一个if else的判断,即如果原本是int_min的话,那我就就仍然置为int_min,即不参与计算,这样就保证了该是负无穷的永远是负无穷

注:int_min+int_min溢出后,在我的电脑上得到结果是0.

代码

#include<iostream>
#include<climits>
#include<algorithm>
#include<cstring>
using namespace std;
int mat[205][205];
int dp[205][205];
int main() {
	int m, n;
	cin >> m >> n;
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			cin >> mat[i][j];
		}
	}
	//边界初始化
	for (int i = 0; i <= m + 1; i++) {
		dp[i][0] = INT_MIN;//初始化左边界
		dp[i][n + 1] = INT_MIN;//初始化右边界
	}
	for (int j = 0; j <= n+1; j++) {//初始化下边界
		dp[m + 1][j] = INT_MIN;
	}
	dp[m + 1][(n + 1) / 2] = 0;

	for (int i = m; i >= 1; i--) {
		for (int j = 1; j <= n; j++) {
			int leftdown, down, rightdown;
			//以下是对有效数字的判断,负无穷增加仍然为负无穷,没有意义
			if (dp[i + 1][j - 1] == INT_MIN) {
				leftdown = INT_MIN;
			}
			else {
				leftdown = dp[i + 1][j - 1] + mat[i][j];
			}

			if (dp[i + 1][j] == INT_MIN) {
				down = INT_MIN;
			}
			else {
				down = dp[i + 1][j] + mat[i][j];
			}

			if (dp[i + 1][j+1] == INT_MIN) {
				rightdown = INT_MIN;
			}
			else {
				rightdown = dp[i + 1][j+1] + mat[i][j];
			}

			dp[i][j] = max({ leftdown,down,rightdown });
		}
	}

	int res = INT_MIN;
	for (int j= 1; j <= n; j++) {
		res = max(res, dp[1][j]);
	}
	cout << res;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值