解析“最大路径和”问题(二):矩阵取数问题(一般方法论讲解+实例应用分析)

深入解析"最大路径和"问题(二):树形动态规划与矩阵取数问题

在上一篇博客中,我们通过二叉树的"最大路径和"问题,详细讲解了树形动态规划的解法。然而,路径问题不仅仅存在于树结构中,矩阵中也有类似的路径最优化 问题。这次我们将进一步扩展,分析矩阵取数的问题。


问题描述:矩阵取数游戏

题目

小明玩一个矩阵取数游戏,规则如下:

  1. 给定一个 n × n n \times n n×n) 的矩阵 a i j a_{ij} aij,其中每个格子的价值 a i j ≥ 0 a_{ij} \geq 0 aij≥0。
  2. 游戏从左上角格子 ( 1 , 1 ) (1, 1) (1,1) 出发,只能向 移动,直到到达右下角格子 ( n , n ) (n, n) (n,n)。
  3. 每经过一个格子,就能获得该格子的价值。
  4. 要求求出从左上角到右下角路径的最大价值和

输入

  • 第一行:矩阵大小 n n n。
  • 接下来的 n n n 行:每行有 n n n个非负整数,表示矩阵格子的价值。

输出

  • 最大价值和。

方法论:动态规划解法

1. 解题思路

矩阵取数问题是一个典型的二维动态规划问题。

动态规划的核心是通过构造一个二维数组 d p dp dp,记录到达每个格子的最大价值和,逐步计算出右下角的最大得分。

状态定义
  • d p i j dpij dpij:表示从左上角到达格子 ( i , j ) (i, j) (i,j) 的最大价值和。
状态转移方程

我们定义: a i j aij aij为矩阵位置 ( i , j ) (i,j) (i,j)的价值。

从起点到达格子 ( i , j ) (i, j) (i,j),只能从上方或左方到达,因此:
d p i j = max ⁡ ( d p i − 1 j , d p i j − 1 ) + a i j dpij = \max(dpi-1j, dpij-1) + a_{ij} dpij=max(dpi−1j,dpij−1)+aij

边界条件
  • 起点 d p 0 0 = a 00 dp00 = a_{00} dp00=a00。
  • 第一行和第一列只能从左或上单向到达:
    • 第一行: d p 0 j = d p 0 j − 1 + a 0 j dp0j = dp0j-1 + a_{0j} dp0j=dp0j−1+a0j
    • 第一列: d p i 0 = d p i − 1 0 + a i 0 dpi0 = dpi-10 + a_{i0} dpi0=dpi−10+ai0

2. 算法步骤

  1. 初始化二维数组 d p dp dp,大小为 n × n n \times n n×n。
  2. 填充边界条件:第一行和第一列的值。
  3. 按照状态转移方程依次填充 d p i j dpij dpij
  4. 返回右下角 d p n − 1 n − 1 dpn-1n-1 dpn−1n−1 的值。

3. 时间复杂度

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2),因为需要填充一个 n × n n \times n n×n 的矩阵。
  • 空间复杂度: O ( n 2 ) O(n^2) O(n2)(可通过滚动数组优化至 O ( n ) O(n) O(n))。

代码实现(C++)

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<vector<int>> matrix(n, vector<int>(n)); // 输入矩阵
    vector<vector<int>> dp(n, vector<int>(n));     // 动态规划数组

    // 输入矩阵值
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            cin >> matrix[i][j];
        }
    }

    // 初始化起点
    dp[0][0] = matrix[0][0];

    // 初始化第一行
    for (int j = 1; j < n; ++j) {
        dp[0][j] = dp[0][j-1] + matrix[0][j];
    }

    // 初始化第一列
    for (int i = 1; i < n; ++i) {
        dp[i][0] = dp[i-1][0] + matrix[i][0];
    }

    // 填充动态规划数组
    for (int i = 1; i < n; ++i) {
        for (int j = 1; j < n; ++j) {
            dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + matrix[i][j];
        }
    }

    // 输出右下角的最大价值和
    cout << dp[n-1][n-1] << endl;

    return 0;
}

实例解析:一步步解决问题

输入示例

text 复制代码
4
1 3 1 2
1 5 1 1
4 2 1 3
1 1 1 10

动态规划表计算

初始化:
  • 起点 d p 0 0 = 1 dp00 = 1 dp00=1
填充第一行和第一列:
i \ j i \backslash j i\j 1 3 1 2
1 1 4 5 7
5 2
4 6
1 7
填充其余格子:

按照状态转移公式逐步计算:

i \ j i \backslash j i\j 1 3 1 2
1 1 4 5 7
5 2 9 10 11
4 6 11 12 15
1 7 12 13 25

输出结果

最终最大价值和为 d p 3 3 = 25 dp33 = 25 dp33=25。


矩阵问题与树问题的对比

特性 树形动态规划 矩阵动态规划
数据结构 矩阵
转移方向 从子树到父节点 从左上角向右下角
优化难点 合理选择路径的起点和终点 优化空间复杂度
时间复杂度 ( O(n) ) ( O(n^2) )

总结与扩展

总结

  • 矩阵取数问题是"最大路径和"问题的二维拓展,核心仍然是动态规划。
  • 状态转移方程清晰,适合由浅入深引导学习。
  • 动态规划思路灵活,稍作调整可用于更复杂的二维路径问题。

扩展问题

  1. 如果允许向四个方向移动(上下左右),如何解决?
  2. 如果要求路径不能重复访问某些特定的格子,该如何修改算法?

希望这篇博客对你理解"最大路径和"问题的多种变体有所帮助!

相关推荐
搬砖魁首12 分钟前
基础能力系列 - 多线程2 - 条件变量
c++·rust·条件变量·原子类型·线程同步互斥
youngerwang18 分钟前
【从搬运工到协处理器:网卡芯片架构、算法、验证与边缘演进深度剖析】
网络·算法·架构·芯片
chase_my_dream20 分钟前
C++ + SLAM 高频面试问题整理
开发语言·c++·面试
牛油果子哥q42 分钟前
【C++ STL string 】C++ STL string 终极精讲:底层原理、内存机制、全套API、深浅拷贝、易错坑点与工程实战规范
数据库·c++
KaMeidebaby42 分钟前
卡梅德生物技术快报|纯化重组蛋白实操详解
人工智能·python·tcp/ip·算法·机器学习
dingzd951 小时前
跨境社媒运营越到后面 越比拼账号的表达稳定性
大数据·人工智能·矩阵·内容营销
手写码匠2 小时前
从零实现 Prompt 工程引擎:结构化提示、自动优化与多轮自省体系
人工智能·深度学习·算法·aigc
无限码力2 小时前
阿里算法岗 0530笔试真题 - 多约束条件下的元素匹配统计
算法·阿里笔试真题·阿里机试真题·阿里算法岗笔试
lqqjuly2 小时前
MLA — 多头潜在注意力深度解析
深度学习·神经网络·算法
吴可可1232 小时前
SolidWorks草图转三维DWG技巧
算法