信息学奥赛一本通题目解析:1258:【例9.2】数字金字塔

文章讲述了如何使用动态规划方法解决数字金字塔中从底部到顶部的路径问题,通过从下到上计算并维护最大路径和,避免了重复计算,最终输出顶部的最大和。
摘要由CSDN通过智能技术生成

【题目描述】

观察下面的数字金字塔。写一个程序查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以从当前点走到左下方的点也可以到达右下方的点。

在上面的样例中,从13到8到26到15到24的路径产生了最大的和86。

【输入】

第一个行包含R(1≤R≤1000),表示行的数目。

后面每行为这个数字金字塔特定行包含的整数。

所有的被供应的整数是非负的且不大于100。

【输出】

单独的一行,包含那个可能得到的最大的和。

【输入样例】

5
13
11 8
12 7  26
6  14 15 8
12 7  13 24 11

【输出样例】

86

解题思路:解决这个问题,可以使用动态规划(Dynamic Programming,DP)的方法。动态规划是解决最优化问题的一个有效方法,特别适用于有重叠子问题和最优子结构性质的问题。

策略:1.从上到下计算,2.从下到上计算

在这个问题中,已知的信息是金字塔的底部,未知的信息是到达顶部的路径和。如果我们从顶部开始计算,就需要考虑所有可能的路径,这会导致大量的重复计算和更高的时间复杂度。所以选择2从下到上计算。

思路分析:首先,需要建立一个二维数组来存储金字塔的每一层数字。然后,从金字塔的底部开始向上计算,每一步都保留到达该位置的最大路径和。

1.状态设计:a[i][j]表示从最下行到第i行第j列的最大值。

2.状态转移方程:a[i][j] += max(a[i + 1][j], a[i + 1][j + 1])。

a[i][j] 在开始时存储了金字塔该位置上的数字,但在动态规划的过程中,它被更新为从该位置到底部的最大路径和。因此,当我们计算 a[i][j] += max(a[i + 1][j], a[i + 1][j + 1]) 时,实际上是将从 (i + 1, j) 和 (i + 1, j + 1) 两个位置到底部的最大路径和中较大的一个,加上当前位置 a[i][j] 的值,来更新 a[i][j]

最终,当所有的状态都更新完毕后,a[1][1] 就存储了从金字塔顶部到底部的最大路径和。最后输出这个值即可。

以下是使用文本表示的简化表格,展示了动态规划的过程:

如下的数字金字塔

3
7 4
2 4 6
8 5 9 3

将通过动态规划填充下面的表格,其中每个单元格(i, j)表示从金字塔的顶部到位置(i, j)的最大路径和。注意,在表格中,我们从第1行开始计数,以便与数组索引保持一致(实际代码中通常从第1行开始计数)。

初始表格(只包含金字塔的数值):

1 | 3
2 | 7 4
3 | 2 4 6
4 | 8 5 9 3

动态规划填充表格的过程(每一步计算最大路径和并更新表格):

第一步(从倒数第二层开始,即第3行):

1 | 3
2 | 7 4
3 | 15 10 13 <- 更新这一行:7+8, 4+5, 4+9
4 | 8 5 9 3

第二步(继续向上到第2行):

1 | 3
2 | 22 14 <- 更新这一行:15+7, max(10,13)+4
3 | 15 10 13
4 | 8 5 9 3

第三步(到达顶部,即第1行):

1 | 25 <- 更新这个单元格:max(22,14)+3
2 | 22 14
3 | 15 10 13
4 | 8 5 9 3

最终,表格顶部的单元格就包含了从金字塔顶部到底部的最大路径和,即25。

在实际代码中,不会创建一个额外的表格来存储中间结果,而是直接在原数组a上进行更新。上面的表格提供了一个可视化的方法来理解动态规划是如何逐步计算最大路径和的。每一步都依赖于前一步的计算结果,并且避免了重复计算相同子问题的解,这是动态规划的关键优势

#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 1005;
int a[MAXN][MAXN];
int main() {
    int R;
    cin >> R; // 输入行数
    for (int i = 1; i <= R; i++)
        for (int j = 1; j <= i; j++)
            cin >> a[i][j]; // 输入数字金字塔
    for (int i = R - 1; i >= 1; i--)
        for (int j = 1; j <= i; j++)
            a[i][j] += max(a[i + 1][j], a[i + 1][j + 1]); // 动态规划计算最大和
    cout << a[1][1] << endl; // 输出结果
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值