【题解】 [CSP-J2020] 方格取数

置顶:一篇超级好的题解,讲得非常细致

 

#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 语句里,和第一条一样。  
对于一个状态来说,他只和他前面(已知)的状态有关(他是从他前面的状态得来的)! 
上一篇:csp-小明放学


下一篇:# 20 图 |6000 字 |实战缓存(上篇)