[动态规划] 洛谷P1216 数字三角形 (DP入门)

题目

这里写图片描述

思路与代码

一.先将问题往适合DP的方向抽象。

1.将当前位置(i,j)看成一个状态,定义状态(i,j)的指标函数 d(i,j)为从位置(i,j)出发能得到的最大和(包括(i,j))。
2.原问题的解:d(1,1)。
3.状态之间是如何转换的,即状态转移方程

d ( i , j ) = G ( i , j ) + m a x ( d ( i + 1 , j ) , d ( i + 1 , j + 1 ) )

4.本问题具有最优子结构的性质, 具体说明

二.计算状态转移方程的方式

1.直接递归计算:

int solve(int i, int j) {
    return G[i][j] + (i == n ? 0 : max(solve(i + 1, j), solve(i + 1, j + 1)));
} 

优点:直接反映状态转移方程,思路明显。
缺点:进行了重复计算(重叠子问题),时间效率低。
复杂度: O ( 2 n )
这里写图片描述
(在此理解一下,重叠子问题的概念)


2.递推:

    int i, j;
    // 先处理最后一层结点
    for (j = 1; j <= n; j++) d[n][j] = G[n][j];

    // 依次逆着枚举出每个结点的决策
    for (i = n - 1; i >= 1; i--)
        for (j = 1; j <= i; j++)
            d[i][j] = G[i][j] + max(d[i + 1][j], d[i + 1][j + 1]);

内容:逆着枚举出所有节点的决策。
在多数情况下,递推法的时间复杂度是:状态总数 x 每个状态决策个数 x 决策时间。
优点:快一些
缺点:需要自己找到结点的决策顺序。
复杂度: O ( n 2 )


3.记忆化搜索

int solve(int i, int j) {
    if (d[i][j] >= 0) return d[i][j];
    return d[i][j] = G[i][j] + (i == n ? 0 : max(solve(i + 1, j), solve(i + 1, j + 1)));
}

内容:递归的时候,顺便记忆一下。。。
优点:快一些,不需要自己找到结点的决策顺序
缺点:需要调用系统栈,所以比递推慢
复杂度: O ( n 2 )

码农小技巧

对于memset进行批量赋值时,只能用-1和0,1、-2、…会乱码。

猜你喜欢

转载自blog.csdn.net/icecab/article/details/80723277