Problem I. Omar Loves Candies【DP】

在这里插入图片描述
在这里插入图片描述


题意

  • 在一个N * M的格子中,放有一些糖,这些糖有的会损害健康,有的对健康有益。有损害的被记为负数,有益的会记为正数。另外,对于每一个糖而言,他都比左边的糖和上面的糖更健康。

  • 现在我要在在N*M这个矩阵中找到一个子矩阵,使得所有糖的有益值加起来最大。


题解

  • 题目很简单,为了方便,逆序输入,使得左上角变为更优糖果
  • 预处理一下,得到任意趋于左上方向的行、列之和。(简单来说就是某个点往左的和、往上的和)
  • 状态转移方程: d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , m a x ( d p [ i 1 ] [ j ] + r o w [ i ] [ j ] , d p [ i ] [ j 1 ] + c o l [ i ] [ j ] ) ) dp[i][j] = max(dp[i][j], max(dp[i - 1][j] + row[i][j], dp[i][j - 1] + col[i][j]))
  • 还有一种不需要DP的方法,时间复杂度相同:遍历所有点, d p [ i ] [ j ] dp[i][j] 记录从起始点(左上角)到这个位置围成的矩形的和。把所有最后遍历一边找最大值。

AC-Code

#include <bits/stdc++.h>
using namespace std;

int mp[maxn][maxn];
int dp[maxn][maxn];
int row[maxn][maxn];
int col[maxn][maxn];

int main() {
	int T;	cin >> T;
	while (T--) {
		int n, m;	cin >> n >> m;
		for (int i = n; i >= 1; --i) {
			for (int j = m; j >= 1; --j) {
				dp[i][j] = -0x3f3f3f;
				cin >> mp[i][j];
			}
		}
		for (int i = 1; i <= n; ++i) {
			for (int j = 1; j <= m; ++j) {
				row[i][j] = row[i][j - 1] + mp[i][j];
				col[i][j] = col[i - 1][j] + mp[i][j];
			}
		}
		for (int i = 1; i <= n; ++i) 
			for (int j = 1; j <= m; ++j) 
				dp[i][j] = max(dp[i][j], max(dp[i - 1][j] + row[i][j], dp[i][j - 1] + col[i][j]));
		int ans = -0x3f3f3f;
		for (int i = 1; i <= n; ++i) 
			for (int j = 1; j <= m; ++j) 
				ans = max(ans, dp[i][j]);
		cout << ans << endl;
	}
	return 0;
}
发布了157 篇原创文章 · 获赞 99 · 访问量 9833

猜你喜欢

转载自blog.csdn.net/Q_1849805767/article/details/104147574