【題解】 [CSP-J2020] 方格取數
阿新 • • 發佈:2021-10-07
#include<iostream> using namespace std; const long long inflw = -1e17; long long n,m; long long mapn[1019][1019]; long long dp[1019][1019][5]; void init(){//初始化 for(int i=0; i<1009; i++) for(int j=0; j<1009; j++) for(int k=0; k<5; k++) dp[i][j][k] = inflw;//要是負無窮 } int main(){ init();//初始化 scanf("%lld %lld",&n,&m); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) scanf("%lld",&mapn[i][j]); dp[1][1][0] = dp[1][1][1] = dp[1][1][2] = mapn[1][1]; for(int i=2; i<=n; i++){ dp[i][1][0] = dp[i-1][1][0]+mapn[i][1]; //從右邊,下邊走不到(i,1),只能從上邊走來 } for(int i=2; i<=m; i++){ for(int j=1; j<=n; j++){ //從(j,i)的上邊來到(j,i) ↓ if(j >= 2)//只有當 j≥2 時才有“上” dp[j][i][0] = max(dp[j-1][i][0],dp[j-1][i][1])+mapn[j][i]; //從(j,i)的左邊來到(j-i) → dp[j][i][1] = max(dp[j][i-1][1],max(dp[j][i-1][0],dp[j][i-1][2]))+mapn[j][i]; } //從(j,i)的下邊來到(j,i) for(int j=n-1; j>=1; j--){//只有當 j=n-1 時才有“下” dp[j][i][2] = max(dp[j+1][i][1],dp[j+1][i][2])+mapn[j][i]; } } printf("%lld",max(dp[n][m][0],max(dp[n][m][1],dp[n][m][2])));// return 0; }
狀態: $dp[x][y][0/1/2]$ : 從 $(1,1)$ 出發,到達 $(x,y)$,每個點只走一次(沒有重複),從上方/右方/下方,最大權值和 0 : 上 1 : 右 2 : 下 坑: 1. 在處理 $dp[j][i][2]$ 的時候,應該寫成
dp[j][i][2] = max(dp[j+1][i][1],dp[j+1][i][2])+mapn[j][i];
而不是
dp[j][i][2] = max(dp[j+1][i][1],max(dp[j+1][i][2],dp[j+1][i][0]))+mapn[j][i];
就是說到一個從 $(j+1,i)$ 到 $(j,i)$ 時,要取 $(j+1,i)$ 的上,右兩個狀態的最大值,因為下的那個狀態和 $dp_{j,i}$ 衝突了。
2. 同理,在 $j$ ≥ $2$ 那個 if 語句裡,和第一條一樣。
對於一個狀態來說,他只和他前面(已知)的狀態有關(他是從他前面的狀態得來的)!