19339201706 发表于 2025-6-19 13:18:56

2020年CSP-J 方格取数问题详解:双向动态规划解法与路径优...



https://dajuwangluo.cn/zb_users/upload/2025/06/202506081749361276775436.jpg

一、问题背景与需求分析题目要求在一个n×m的方格矩阵中,从左上角(0,0)出发到右下角(n-1,m-1),每次可以向右、向上或向下移动,找出路径上数字之和最大的路线。核心难点:
[*]路径方向多样性(右、上、下)
[*]避免路径交叉和循环
[*]需要考虑来自不同方向的最优解
二、完整代码实现(带详细注释)
#include <iostream>
#include <vector>
#include <algorithm>
using namespACe std;

const int INF = 1e9;// 定义无穷大值

int main() {
    ios::sync_with_stdio(false);// 关闭同步提升IO速度
    cin.tie(nullptr);             // 解除cin与cout的绑定
   
    int n, m;
    cin >> n >> m;
   
    // 读取网格数据
    vector<vector<int>> grid(n, vector<int>(m));
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < m; ++j) {
            cin >> grid;
      }
    }
   
    // 三维DP数组:dp表示从上方到达(i,j)的最大和
    // dp表示从下方到达(i,j)的最大和
    vector<vector<vector<long long>>> dp(n, vector<vector<long long>>(m, vector<long long>(2, -INF)));
   
    // 初始化起点
    dp = dp = grid;
   
    // 处理第一列(只能从上到下)
    for (int i = 1; i < n; ++i) {
      dp = dp = dp + grid;
    }
   
    // 动态规划处理(按列处理)
    for (int j = 1; j < m; ++j) {
      // 从上到下处理当前列
      for (int i = 0; i < n; ++i) {
            if (i == 0) {// 第一行只能从左边来
                dp = max(dp, dp) + grid;
            } else {// 可以从左边或上方来
                dp = max({dp, dp, dp}) + grid;
            }
      }
      
      // 从下到上处理当前列
      for (int i = n-1; i >= 0; --i) {
            if (i == n-1) {// 最后一行只能从左边来
                dp = max(dp, dp) + grid;
            } else {// 可以从左边或下方来
                dp = max({dp, dp, dp}) + grid;
            }
      }
    }
   
    // 输出结果(取两种方向中的最大值)
    cout << max(dp, dp) << endl;
   
    return 0;
}

三、算法核心思想解析
[*]三维DP设计:

[*]第三维/分别表示从上/从下到达该点
[*]避免路径方向冲突
[*]双向处理策略:

[*]每列先从上到下计算(考虑来自左和上的路径)
[*]再从下到上计算(考虑来自左和下的路径)
[*]边界处理:

[*]第一列只能垂直移动
[*]第一行和最后一行有特殊处理

链接:动态规划
页: [1]
查看完整版本: 2020年CSP-J 方格取数问题详解:双向动态规划解法与路径优...