最优化问题:有nnn个输入,问题解由nnn个输入的一个子集组成,这个子集必须满足某些事先给定的条件,这些条件称为约束条件
这类问题就称之为最优化问题
动态规划:1957年,美国数学家Richard Bellman等人在研究多阶段决策问题的最优性原理中,创建了一种最优化问题求解方法——动态规划。动态规划算法的基本思想和分治法类似,即也将待求解问题分解为若干子问题,但是经分解得到的子问题往往不是相互独立的(也即是相互重叠的),每个子问题是问题求解过程中的一个阶段

分治法在解决适合用动态规划解决的题目时会重复计算公共子问题,效率极低,甚至在求解多项式量级的子问题数目时也可能耗费指数时间

动态规划在解决问题时会用一个表保存此阶段子问题的解,当下一求解阶段需要再次计算此子问题时可以通过查表获得该子问题的解而不用再次求解,从而避免了大量重复计算

最后需要重复一下,动态规划解决的问题一定具有最优子结构的性质。什么是最优子结构呢,举个例子:你们年级有20个班,并且已经知道每个班的最高分,那么全年级成绩最高分是多少?我想在这样的情况下,你肯定不会遍历全年级同学,而是会直接比较每个班的最高分然后得出结论。所以这里 “班级最高”就是“全年级最高”的最优子结构
付款问题:超时的POS机要找给顾客货币数量最少的现金
假定POS机中有nnn张面值为pi(1≤i≤n)p_{i}(1\leq i \leq n)pi(1≤i≤n)的货币,用集合P={p1,p2,...,pn}P=\{p_{1},p_{2},...,p_{n}\}P={p1,p2,...,pn}表示,如果POS机需支付的现金为AAA(问题的输入)。那么它必须从PPP中选取一个最小子集SSS,使得
pi∈s,∑i=1mpi=A(m=∣S∣)p_{i}\in s,\quad\sum\limits_{i=1}^{m}p_{i}=A(m=|S|)pi∈s,i=1∑mpi=A(m=∣S∣)
如果用向量X=(x1,x2,...,xn)X=(x_{1}, x_{2},...,x_{n})X=(x1,x2,...,xn)(解向量)表示SSS中选取货币的结果,则
xi={1pi∈S0pi∉Sx_{i}=\left\{ \begin{aligned} 1 & \quad p_{i}\in S \\ 0 & \quad p_{i}\notin S \\ \end{aligned} \right. xi={10pi∈Spi∈/S
那么POS机支付的现金必须满足
∑i=1mpi=A\sum\limits_{i=1}^{m}p_{i}=Ai=1∑mpi=A
并且
d=min∑i=1mpid=min\sum\limits_{i=1}^{m}p_{i}d=mini=1∑mpi
动态规划论题目五花八门,但如果你做得多了,你会发现这类题目的代码具有一个特点,那就是多重for循环
# 初始化“最简单情况”
dp[0][0][...]=base case;
# 状态转移
for 状态1 in 状态1 的所有取值for 状态 2 in 状态2的所有取值for...dp[状态1][状态2][...]=求最值(选择1,选择2,...);
动态规划算法步骤:动态规划算法会涉及如下三个基本要素,写动态规划算法的过程就必须对这三个要素逐个击破
其中重叠子问题和最优子结构相对来说比价容易解决,而 状态转移方程直接决定了你是否可以做出相应的题目,所以在写状态转移方程前你一定要思考以下几点