算法学习——动态规划实践

动态规划实践:数字三角形

完成日期:2017.10.26


实验内容

1. 实践题目

数字三角形

2. 问题描述

给定一个由 n行数字组成的数字三角形如下图所示。试设计一个算法,计算出从三角形 的顶至底的一条路径(每一步可沿左斜线向下或右斜线向下),使该路径经过的数字总和最大。

这里写图片描述

3. 算法描述

1)首先该问题有最优子结构和重叠子问题的性质,因此可以用动态规划来求解。
2)设 a[i][j] 表示数字三角形中的第 i 行第 j 个点;
3)max[i][j]表示 第 i 行 第 j 个数字到低端的最优路径值,则原问题的最优解就是 max[1][1] 的值;
4)从 a[i][j] 这个点向下走,有 a[i +1][j] 和a[i+1][j+1] 这两个点可以选择; 则 max[i][j] 的最优值 = a[i][j] 的值 + max{ max[i+1][j] ,max[i+1][j+1] }。
5)因为原问题的最优解是 max[1][1],因此填表的顺序就是至底向上,先计算最后一层的点,然后倒数二层,……,一直算到第一层。
递归公式:
max[i][j]:第 i 行 第 j 个数字到低端的最优路径值。
max[i][j] = a[i][j] ( i=n)
max[i][j] = max{ max[i-1][j], max[i-1][j+1] } + a[i][j] ( 1 <= i <= j < n)
原问题的最优值是 b[1][1]

4. 算法时间及空间复杂度分析

时间复杂度:
因为三角形的数字总和为n(n+1)/2,因此填表的时候会有两重循环:行数 i 和列数j 的循环,得到的时间复杂度为o(n²)。
空间复杂度:
算法需要一个记录子结构最优解的二维数组max,这个数组的规模为n行n列,因此空间复杂度为o(n²)。

5. 程序代码
#include <iostream>

using namespace std;

int a[101][101];

int longestPath(int n){
    for (int i=n-1; i>=1; i--){
        for (int j=i; j>=1; j--){
            if(a[i+1][j] >= a[i+1][j+1])
                a[i][j] += a[i+1][j];
            else
                a[i][j] += a[i+1][j+1];
        }
    }
    return a[1][1];
}


int main() {
    int n;
    cin>>n;
    for (int i=1; i<=n; i++)
        for (int j=1; j<=i; j++)
            cin>>a[i][j];
    cout << longestPath(n) << endl;
    return 0;
}

6. 程序运行截图

这里写图片描述

7. 心得体会

首先在了解了题目,知道它可以用动态规划来解决之后,我一开始想到的是用一个一维数组来记录每一层的最优解,自上而下来记录,但是按照这个思路来想,一直在研究 max[i] 和 max[i+1] 怎么搭上关系,后来发现无论是从下到上还是从上到下,怎么样都没有办法记录,这时候我就知道自己的方向想错了,可能是理解错了动态规划的意思,然后我赶紧复习了一下动态规划。
后来想到了用一个二维数组来记录每个节点的最优解,我手动填了一次表格,发现从下到上还是从上到下写起都是可以的,但是从下到上写的话最后可以马上得到 max[1][1] 就是最优解。但是从上到下写最后就必须对最底的那一排进行遍历取得最大值,因此顺序从上到下比较省时和方便。
接下来程序就很顺利地完成了,最后一个问题是在记录节点的最优解时,可以选择另开一个二维数组max来记录最优解,也可以直接覆盖记录原始数据的数组a,如果新开一个数组的话就会算法的空间复杂度增加,但是如果覆盖的话,原始数据就会丢失,因此需要根据实际的情景选择适合的操作方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值