1. 程式人生 > 實用技巧 >luoguP7074(CSP-J2)方格取數題解

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}} $ ;

$ f_{i,j,1} = \max {f_{i+1,j,1},f_{i,j-1,0/1}} $ ;

答案就是 $ 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;
}