查看: 28|回复: 0

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

[复制链接]
  • TA的每日心情
    无聊
    昨天 10:41
  • 签到天数: 12 天

    [LV.3]偶尔看看II

    10

    主题

    0

    回帖

    37

    积分

    新手上路

    Rank: 1

    积分
    37
    发表于 2025-6-22 10:32:10 | 显示全部楼层 |阅读模式



    一、问题背景与需求分析
    题目要求在一个n×m的方格矩阵中,从左上角(0,0)出发到右下角(n-1,m-1),每次可以向右、向上或向下移动,找出路径上数字之和最大的路线。
    核心难点
    • 路径方向多样性(右、上、下)
    • 避免路径交叉和循环
    • 需要考虑来自不同方向的最优解

    二、完整代码实现(带详细注释)
    1. #include <iostream>
    2. #include <vector>
    3. #include <algorithm>
    4. using namespace std;

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

    6. int main() {
    7.     ios::sync_with_stdio(false);  // 关闭同步提升IO速度
    8.     cin.tie(nullptr);             // 解除cin与cout的绑定
    9.    
    10.     int n, m;
    11.     cin >> n >> m;
    12.    
    13.     // 读取网格数据
    14.     vector<vector<int>> grid(n, vector<int>(m));
    15.     for (int i = 0; i < n; ++i) {
    16.         for (int j = 0; j < m; ++j) {
    17.             cin >> grid[i][j];
    18.         }
    19.     }
    20.    
    21.     // 三维DP数组:dp[i][j][0]表示从上方到达(i,j)的最大和
    22.     // dp[i][j][1]表示从下方到达(i,j)的最大和
    23.     vector<vector<vector<long long>>> dp(n, vector<vector<long long>>(m, vector<long long>(2, -INF)));
    24.    
    25.     // 初始化起点
    26.     dp[0][0][0] = dp[0][0][1] = grid[0][0];
    27.    
    28.     // 处理第一列(只能从上到下)
    29.     for (int i = 1; i < n; ++i) {
    30.         dp[i][0][0] = dp[i][0][1] = dp[i-1][0][0] + grid[i][0];
    31.     }
    32.    
    33.     // 动态规划处理(按列处理)
    34.     for (int j = 1; j < m; ++j) {
    35.         // 从上到下处理当前列
    36.         for (int i = 0; i < n; ++i) {
    37.             if (i == 0) {  // 第一行只能从左边来
    38.                 dp[i][j][0] = max(dp[i][j-1][0], dp[i][j-1][1]) + grid[i][j];
    39.             } else {  // 可以从左边或上方来
    40.                 dp[i][j][0] = max({dp[i][j-1][0], dp[i][j-1][1], dp[i-1][j][0]}) + grid[i][j];
    41.             }
    42.         }
    43.         
    44.         // 从下到上处理当前列
    45.         for (int i = n-1; i >= 0; --i) {
    46.             if (i == n-1) {  // 最后一行只能从左边来
    47.                 dp[i][j][1] = max(dp[i][j-1][0], dp[i][j-1][1]) + grid[i][j];
    48.             } else {  // 可以从左边或下方来
    49.                 dp[i][j][1] = max({dp[i][j-1][0], dp[i][j-1][1], dp[i+1][j][1]}) + grid[i][j];
    50.             }
    51.         }
    52.     }
    53.    
    54.     // 输出结果(取两种方向中的最大值)
    55.     cout << max(dp[n-1][m-1][0], dp[n-1][m-1][1]) << endl;
    56.    
    57.     return 0;
    58. }
    复制代码


    三、算法核心思想解析
    • 三维DP设计

      • 第三维[0]/[1]分别表示从上/从下到达该点
      • 避免路径方向冲突

    • 双向处理策略

      • 每列先从上到下计算(考虑来自左和上的路径)
      • 再从下到上计算(考虑来自左和下的路径)

    • 边界处理

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

    四、复杂度分析与优化
    • 时间复杂度:O(n×m) 每个格子处理两次
    • 空间优化:可降维到O(n)只存储前一列数据
    • 实际应用:可扩展到三维路径规划问题

    五、常见错误与调试技巧
    • 初始化问题:忘记初始化起点
    • 方向混淆:上下方向处理错误
    • 边界条件:行列边界处理不当
    • 调试建议:打印每步DP值验证


    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    快速回复 返回顶部 返回列表