数字三角形
题目理解
这道题目描述了一个数字金字塔结构,要求从顶部到底部找到一条路径,使得路径上的数字之和最大。每一步可以选择移动到左下方或右下方的数字。
输入要求:
- 
第一行一个整数r,表示金字塔的行数 
- 
接下来r行,每行包含对应行数的整数,构成数字金字塔 
输出要求:
- 
一个整数,表示可能得到的最大路径和 
解题思路
1. 问题分析
这是一个典型的动态规划问题,具有以下特点:
- 
最优子结构:整体最优解包含子问题的最优解 
- 
重叠子问题:计算过程中会重复访问相同的子问题 
- 
无后效性:当前状态只与之前状态有关,与之后状态无关 
2. 递推关系
我们可以从下往上思考,也可以从上往下思考。这里采用从上往下的动态规划方法:
- 
状态定义: a[i][j]表示到达第i行第j列位置时的最大路径和
- 
初始状态: a[1][1]就是金字塔顶端的数字
- 
状态转移方程: - 
对于第i行第j列的位置,它可以从第i-1行的第j-1列或第j列移动而来 
- 
因此, a[i][j] = max(a[i-1][j-1], a[i-1][j]) + 当前数字
 
- 
- 
最终结果:遍历最后一行的所有 a[n][j],取最大值
3. 算法优化
实际上,我们可以在填充a[i][j]的同时记录当前最大值,这样就不需要最后再遍历一次最后一行。这就是代码中ans = max(ans, a[i][j])的作用。
参考代码
#include<bits/stdc++.h>
using namespace std;
int a[1005][1005], n, ans; // a数组存储金字塔及动态规划结果,n是行数,ans记录最大值
int main() {
    // 读取输入
    cin >> n; // 读取金字塔的行数
    
    // 动态规划处理
    for (int i = 1; i <= n; i++) { // 遍历每一行
        for (int j = 1; j <= i; j++) { // 遍历当前行的每个数字
            cin >> a[i][j]; // 读取当前数字
            
            // 状态转移方程:
            // 当前数字加上上方两个数字中较大的一个
            a[i][j] = max(a[i - 1][j], a[i - 1][j - 1]) + a[i][j];
            
            // 更新全局最大值
            ans = max(ans, a[i][j]);
        }
    }
    
    // 输出结果
    cout << ans;
    return 0;
}复杂度分析
- 
时间复杂度:O(n²),其中n是金字塔的行数。因为我们需要处理n行,第i行有i个元素。 
- 
空间复杂度:O(n²),用于存储金字塔和动态规划结果。 
示例推演
以题目中的样例为例,我们来看动态规划的过程:
初始金字塔:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5动态规划过程:
- 
第一行: a[1][1] = 7
- 
第二行: - 
a[2][1] = max(0, 7) + 3 = 10(左边没有元素视为0)
- 
a[2][2] = max(7, 0) + 8 = 15
 
- 
- 
第三行: - 
a[3][1] = max(0, 10) + 8 = 18
- 
a[3][2] = max(10, 15) + 1 = 16
- 
a[3][3] = max(15, 0) + 0 = 15
 
- 
- 
以此类推... 
最终得到的最大路径和为30,对应路径7→3→8→7→5。
总结
这道题目展示了动态规划在解决最优化问题中的强大能力。通过定义合适的状态和状态转移方程,我们可以高效地解决看似复杂的问题。这种自顶向下的动态规划方法直观易懂,是解决金字塔/三角形类问题的经典方法。
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号