luoguP7074(CSP-J2)方格取数题解
题面简述:给你一个 $ n \times m $ 的矩阵,从左上角走到右下角,每次可以向上,下,右三个方向走,问所能取到数的和的最大值。
数据范围:$ 1\leq n,m \leq 10^3 , -10^4 \leq a_{i,j} \leq 10^4 $ 。
题解:
一看就是直接线性DP。
设 $ f_{i,j,0} $ 表示在第 $ j $ 列向下走所能取得的数的最大值,$ f_{i,j,1} $ 表示在第 $ j $ 列向上走所能取得的数的最大值。
于是转移方程就很显然了,直接摆在这里,就不解释了。
$ f_{i,j,0} = \max ({f_{i-1,j,0},f_{i,j-1,0/1}}) + a_{i,j} $ ;
$ f_{i,j,1} = \max ({f_{i+1,j,1},f_{i,j-1,0/1}}) + a_{i,j} $ ;
答案就是 $ f_{n,m,0} $ 。
边界什么的具体看代码:
#include <bits/stdc++.h>
using namespace std;
#define max(x,y) ((x)>(y)?(x):(y))
#define int long long
inline int read(){
int f=1,r=0;char c=getchar();
while(!isdigit(c))f^=c=='-',c=getchar();
while(isdigit(c))r=(r<<1)+(r<<3)+(c^48),c=getchar();
return f?r:-r;
}
const int N=1e3+5,inf=1e11;
int n,m,a[N][N],f[N][N][2];
signed main(){
n=read(),m=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
a[i][j]=read();
for(int i=1;i<=n;i++)f[i][0][0]=f[i][0][1]=-inf;//因为有负数,所以设成-inf。
for(int i=2;i<=m;i++)f[0][i][0]=f[n+1][i][0]=f[0][i][1]=f[n+1][i][1]=-inf;
for(int j=1;j<=m;j++){
if(j==1 || j==m)//第一列与第n列显然只能往下走
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],f[i][j][1]=-inf;
else{
for(int i=1;i<=n;i++)
f[i][j][0]=max(max(f[i-1][j][0],f[i][j-1][0]),f[i][j-1][1])+a[i][j];
for(int i=n;i;i--)
f[i][j][1]=max(max(f[i+1][j][1],f[i][j-1][1]),f[i][j-1][0])+a[i][j];
}
}
return cout<<f[n][m][0],0;
}