#P7074 [CSP-J 2020] 方格取数

[返回题解]


题目速览

题目描述

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

输入格式

第一行有两个整数 n,mn, m。

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

输出格式

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

输入输出样例 #1

输入 #1

3 4
1 -1 3 2
2 -1 4 -1
-2 2 -3 -1

输出 #1

9

输入输出样例 #2

输入 #2

2 5
-1 -1 -3 -2 -7
-2 -1 -4 -1 -2

输出 #2

-10

说明/提示

样例 1 解释

样例 2 解释

数据规模与约定

  • 对于 20%20\% 的数据,n,m≤5n, m \le 5。
  • 对于 40%40\% 的数据,n,m≤50n, m \le 50。
  • 对于 70%70\% 的数据,n,m≤300n, m \le 300。
  • 对于 100%100\% 的数据,1≤n,m≤1031 \le n,m \le 10^3。方格中整数的绝对值不超过 10410^4。

一道 普及+/提高− 的dpdp题

  • 定义状态

...,从图的左上角走到右下角,每一步只能向上、向下或向右走一格,并且不能重复经过已经走过的方格,也不能走出边界...

由↑可知,这只小熊在同一列选择向上走时,不能再向下走,反之同理。所以可以这样定义状态:

定义状态

定义sh[i][j]sh[i][j]为在第jj列中,路径从该列的‌上方‌最终到达(i,j)(i,j) 时的最大和。

定义‌x[i][j]x[i][j]为在第jj列中,路径从该列的‌下方‌最终到达(i,j)(i,j)时的最大和。

定义dp[i][j]dp[i][j]为到达坐标(i,j)(i,j)时,所能获得的‌最大和。


  • 初始化

因为小熊从(1,1)(1,1)出发,所以在第一列只能往下走。

代码
for(int i=1;i<=n;i++) s+=a[i][1],dp[i][1]=s,sh[i][1]=MINN,xi[i][1]=s;

  • 状态转移方程

状态转移方程 sh[i][j]=max(dp[i][j−1],sh[i−1][j])+a[i][j](i>1)sh[i][j]=max(dp[i][j−1],sh[i−1][j])+a[i][j](i>1) xi[i][j]=max(dp[i][j−1],xi[i+1][j])+a[i][j](i<n)xi[i][j]=max(dp[i][j-1],xi[i+1][j])+a[i][j](i<n) dp[i][j]=max(sh[i][j],xi[i][j])dp[i][j]=max(sh[i][j],xi[i][j])

特殊:

sh[1][j]=dp[1][j−1]+a[1][j]sh[1][j]=dp[1][j−1]+a[1][j] xi[n][j]=dp[n][j−1]+a[n][j]xi[n][j]=dp[n][j−1]+a[n][j]

  • 答案

答案 dp[n][m]dp[n][m]

代码部分
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=1e3+5,MINN=INT_MIN;
ll s,dp[MAXN][MAXN],a[MAXN][MAXN],sum,sh[MAXN][MAXN],xi[MAXN][MAXN],n,m;
int main(){
    cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			cin>>a[i][j];

	for(int i=1;i<=n;i++) s+=a[i][1],dp[i][1]=s,sh[i][1]=MINN,xi[i][1]=s;//初始化
	for(int j=2;j<=m;j++){
		for(int i=1;i<=n;i++) sum=dp[i][j-1],sum=(i>1 ? max(sum,sh[i-1][j]):dp[i][j-1]),sh[i][j]=sum+a[i][j];
		for(int i=n;i>=1;i--) sum=dp[i][j-1],sum=(i<n ? max(sum,xi[i+1][j]):dp[i][j-1]),xi[i][j]=sum+a[i][j];
		for(int i=1;i<=n;i++) dp[i][j]=max(sh[i][j],xi[i][j]);
	}
	cout<<dp[n][m];
	return 0;
}
//fish code