动态规划学习笔记

98 阅读2分钟

本文大纲

算法了解

动态规划基本思想

动态规划主要的思想有以下几点:

  1. 将复杂问题拆分为一个个子问题,再由子问题推算出原问题
  2. 将重复使用的量记录下来(类似于记忆化)

表情包

一个例题了解动态规划

动态规划五部曲

很多人“学会”了动态规划就是背过代码,照葫芦画瓢。一遇到变形题就不会了,所以,想要真正掌握动规,需要掌握动态规划五部曲才行:

  1. 定义状态(即确定f数组的含义)
  2. 确认状态转移方程(即递推式)
  3. 初始化f数组
  4. 确认循环顺序
  5. 举例推导验证

例题解析

来看一道例题:P1216 数字三角形

我们按照动态规划五部曲解决此题。

定义状态

这道题定义状态没什么难度,定义f[i][j]为从第i行第j个数到最后一行的最大价值。

确认状态转移方程

首先思考:f[i][j]如何得来?很明显,对于可选的两条路径,选取最大值即可。所以状态转移方程为f[i][j]+=max(f[i+1][j],f[i+1][j+1])。之所以是+=,因为还需要加上本身价值,故为+=

初始化数组

这道题因为需要加上本身价值,上面用的是价值,所以用输入的三角形初始化即可。

确认循环顺序

由于每一个推导依赖于下一行,所以显然要从下往上推导。

举例推导验证

留给读者自己验证。

代码

确认了以上五点,代码基本可以得出:

#include<iostream>
using namespace std;
int f[1100][1100],n;
int main(){
    cin >> n;
    for (int i = 1;i <= n;++i){
        for (int j = 1;j <= i;++j) cin >> f[i][j]; 
    }
    for (int i = n - 1;i >= 1;--i){ 
        for (int j = 1;j <= i;++j) f[i][j] += max(f[i + 1][j],f[i + 1][j + 1]); 
    }
    cout << f[1][1]; 
	return 0;
}

本文使用 文章同步助手 同步