题目描述
设有 𝑛 × 𝑚 的方格图,每个方格中都有一个整数。现有一只小熊,想从图的左上角走到右下角,每一步只能向上、向下或向右走一格,并且不能重复经过已经走过的方格,也不能走出边界。小熊会取走所有经过的方格中的整数,求它能取到的整数之和的最大值。
输入
输入文件名为 number.in。
第 1 行两个正整数 𝑛, 𝑚。
接下来 𝑛 行每行 𝑚 个整数,依次代表每个方格中的整数。
输出
输入文件名为 number.out。
一个整数,表示小熊能取到的整数之和的最大值。
样例输入
【样例 1 输入】
3 4
1 -1 3 2
2 -1 4 -1
-2 2 -3 -1
【样例 2 输入】
2 5
-1 -1 -3 -2 -7
-2 -1 -4 -1 -2
样例输出
【样例 1 输出】
9
【样例 2 输出】
-10
数据范围限制
对于 20% 的数据,𝑛, 𝑚 ≤ 5。
对于 40% 的数据,𝑛, 𝑚 ≤ 50。
对于 70% 的数据,𝑛, 𝑚 ≤ 300。
对于 100% 的数据,1 ≤ 𝑛, 𝑚 ≤ 1000。方格中整数的绝对值不超过 104。
解题:
题目大意:
给出一个 n × m n×m n×m的矩阵,每个格子有个权值,求从左上角到右下角的在大权值和(可以往右,上,下走)。
思路:
这道题用肉眼看都是用DP,但正常的DP做这道题不能向上走,所以我们考虑分类讨论:
从左边来的(i,j)的最大权值和为lefti,j ;
从上边来的(i,j)的最大权值和为upi,j ;
从下边来的(i,j)的最大权值和为downi,j 。
然而DP式显而易见:
- left可以从left,up,down更新;
- up可以从left,up更新;
- down可以从left,down更新;
更新的过程就和普通DP一样,注意顺序。
代码:
#include<cstdio>
#define Fu(i,a,b) for(int i=(a);i<=(b);i++)
#define Fd(i,a,b) for(int i=(a);i>=(b);i--)
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define INF 11999999999
long long n,m,a[1005][1005],up[1005][1005],down[1005][1005],left[1005][1005];//不开long long见祖宗
long long max(long long x,long long y){
if(x>y)return x;
return y;
}
int main(){
fre(number);
scanf("%lld%lld",&n,&m);
Fu(i,1,n)Fu(j,1,m){
scanf("%lld",&a[i][j]);
up[i][j]=down[i][j]=left[i][j]=-INF;
}
up[1][1]=down[1][1]=left[1][1]=a[1][1];
Fu(j,1,m){
Fu(i,1,n){//先转移up和left
if(i!=1) up[i][j]=max(up[i-1][j],left[i-1][j])+a[i][j];
if(j!=1) left[i][j]=max(left[i][j-1],max(up[i][j-1],down[i][j-1]))+a[i][j];
}
Fd(i,n-1,1)down[i][j]=max(down[i+1][j],left[i+1][j])+a[i][j];
}
printf("%lld",max(up[n][m],left[n][m]));
fclose(stdin);
fclose(stdout);
return 0;
}