「学习笔记」动态规划的引入
一.什么是动态规划
动态规划是一种重要的思维方法,通过利用已有的子问题信息高效求出当前问题的最优解。
由于动态规划并不是某种具体的算法,而是一种解决特定问题的方法,因此它会出现在各式各样的数据结构中,与之相关的题目种类也更为繁杂。
二.动态规划基础
一般的,对于解决动态规划的题目,有以下三个步骤:
- 1.根据题目设计状态,初始化状态。
- 2.根据状态,推导转移方程。(也就是考虑如何从 \(i-1\) 转移到 \(i\))
- 3.确定最优解,求出答案。
而动态规划与贪心算法本质上的区别在于:贪心算法算出的是局部最优解,而动态规划算出的是全局最优解。所以我们要认真读题,避免判断错误。
三.基本例题入门
-
P1216 [USACO1.5][IOI1994]数字三角形 Number Triangles
读题,按照上文分 \(3\) 步:- 1.设立状态: \(dp_{i,j}\) 表示从起点到点 \(i,j\) 的最大价值,初始化 \(dp_{1,1}=a_{1,1}\)。
- 2.推导转移方程:发现当前的 \(dp_{i,j}\) 有两条路可以得到:从点 \(i-1,j-1\) 或点 \(i-1,j\),也就是当前点上一层的两个点。于是转移方程为 \(dp_{i,j}=\text{max}(dp_{i-1,j},dp_{i-1,j-1})+a_{i,j}\)。
- 3.确定最优解:题目要求求到达最底层所获得的最大值。根据我们设计的状态,也就是求 \(\text{max}(dp_{r,i})\)。
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e3 + 7; int dp[N][N], n, a[N][N]; int main () { cin >> n; for (int i = 1; i <= n; i ++) { for (int j = 1; j <= i; j ++) { cin >> a[i][j]; } } for (int i = 1; i <= n; i ++) { for (int j = 1; j <= i; j ++) { dp[i][j] = max (dp[i - 1][j], dp[i - 1][j - 1]) + a[i][j]; } } int ans = 0; for (int i = 1; i <= n; i ++) { ans = max (ans, dp[n][i]); } cout << ans; return 0; }