分析动态规划的核心四步法
训练目标:学会对采用四步法分析和解决问题,而不是代码实现。
训练内容:简单线性动态规划问题的分析
核心分析四步法:
- 定义状态:能够准确定义问题状态;
- 状态转移方程:能够对问题进行分解;
- 初始状态:能够确定边界状态;
- 计算顺序:总结 dp 公式。
【问题 1】最小花费
题目描述
数组的每个下标作为一个阶梯,第 \(i\) 个阶梯对应着一个非负数的体力花费值 \(\text{cost}[i]\)(下标从 \(1\) 开始)。
每当你爬上一个阶梯,都要花费对应的体力值,一旦支付了相应的体力值,就可以选择向上爬一个阶梯或者爬两个阶梯。
求:求出到达楼层顶部的最低花费。
在开始时,从下标为 \(1\) 或者 \(2\) 的元素作为初始阶梯。
分析过程
1. 状态是什么?
使用函数表示,并在描述的状态中体现出问题规模信息和想要得结果。
\(\boldsymbol{dp(n)}\):从第 1 或者第 2 阶到达第 \(n\) 阶的最小代价。
2. 如何分解?
考虑最后一步,对最后一步进行分类讨论,需要能够用到前面已求状态。
从哪一台阶跳一次恰好能够到达第 \(n\) 阶,有两种情况:
- 从第 \(n-1\) 阶,跳 \(1\) 阶,花费值为 \(dp(n-1) + cost[n-1]\);
- 从第 \(n-2\) 阶,跳 \(2\) 阶,花费值为 \(dp(n-2) + cost[n-2]\)。
两种情况取最小值。
3. 边界值?
问题的初始状态,无需通过状态转移方程就能得到结果:
可以直接从第 1 阶或第 2 阶起跳,所以:
\(dp(1) = dp(2) = 0\)
4. 总结 dp 公式:
【问题 2】B3636 文字工作
题目描述
机器猫要在电脑前打字。一共需要打 \(n\) 个字,但现在文档里只有一个字。
机器猫有两种操作可以做。假设现在已经有 \(x\) 个字,机器猫可以选择:
- 往文档最后加一个字。字数变成 \(x+1\)。
- 把文档复制粘贴一遍。字数变成 \(2x\)。
问机器猫至少需要多少次操作,才能得到恰好 \(n\) 个字。
输入格式
仅一行,一个正整数 \(n\)。
输出格式
仅一行,一个正整数,表示最少操作次数。
输入输出样例
| 输入样例 1 | 输出样例 1 |
|---|---|
16 |
4 |
| 输入样例 2 | 输出样例 2 |
|---|---|
5 |
3 |
说明 / 提示
样例解释
- 样例数据 1:\(1 \to 2 \to 4 \to 8 \to 16\),共 4 步。
- 样例数据 2:\(1 \to 2 \to 4 \to 5\),共 3 步。
数据规模与约定
对于 \(100\%\) 的数据,\(n \le 10^6\)。
分析过程
1、确定状态:
\(\boldsymbol{dp(x)}\):表示从 1 个字刚好得到 \(x\) 个字的最少操作次数。
2、分解问题:
考虑最后一步操作从什么状态可以刚好得到 \(x\) 个字:
- 从 \(dp(x-1)\) 的状态下执行第一个操作(加一个字);
- 当 \(x\) 为大于 0 的偶数时,从 \(dp(x/2)\) 的状态下执行第二个操作(复制粘贴)。
两种情况取最小值。
3、问题边界:
当只有 1 个字符的时候,无需任何操作:
\(dp(1) = 0\)
4、总结 dp 公式:
【问题 3】奶牛渡河 1
题目描述
Farmer John 以及他的 \(N(1 \le N \le 2,500)\) 头奶牛打算过一条河,但他们所有的渡河工具,仅仅是一个木筏。由于奶牛不会划船,在整个渡河过程中,FJ 必须始终在木筏上。
在这个基础上,木筏上的奶牛数目每增加 1,FJ 把木筏划到对岸就得花更多的时间。
当 \(FJ\) 一个人坐在木筏上,他把木筏划到对岸需要 \(M(1 \le M \le 1000)\) 分钟。
当木筏搭载的奶牛数从 \(i-1\) 增加到 \(i\) 时,FJ 得多花 \(M_i(1 \le M_i \le 1000)\) 分钟才能把木筏划过河(也就是说,船上有 1 头奶牛时,FJ 得花 \(M+M_1\) 分钟渡河;船上有 2 头奶牛时,时间就变成 \(M+M_1+M_2\) 分钟。后面的依此类推)。
那么,FJ 最少要花多少时间,才能把所有奶牛带到对岸呢?
这个时间不包括 FJ 一个人把木筏从对岸划回来接下一批的奶牛的时间。
输入格式
第 1 行:2 个用空格隔开的整数:\(N\) 和 \(M\)。
第 \(2 \dots N+1\) 行:第 \(i+1\) 行为 1 个整数:\(M_i\)。
输出格式
1 行:输出 1 个整数,为 FJ 把所有奶牛都载过河所需的最少时间。
输入输出样例
输入 #1
5 10
3
4
6
100
40
输出 #1
50
分析过程
1、定义状态:
\(\boldsymbol{dp(i)}\):表示前 \(i\) 头奶牛渡河的最少时间。
2、分解问题:
考虑最后一组有 \(j\) 头奶牛过河,那么需要知道:
- 前 \(n-j\) 头奶牛的最少花费时间 \(dp(n-j)\)
- 一组 \(j\) 头奶牛的渡河时间
其中 \(j\) 的取值范围是 \([1, i]\)。
渡河时间为 \(M\)(人的基础时间)加上 \(M_1\) 到 \(M_j\) 的总和(每头奶牛的附加时间)。
3、问题边界:
\(i=0\) 时候,没有奶牛需要渡河,直接可以得:
\(dp(0) = 0\)
4、总结 dp 公式:
其中 \(\text{cost}(j) = M + \sum\limits_{k=1}^{j} M_k\),表示载 \(j\) 头奶牛一次过河的时间。
【问题 4】奶牛渡河 2
题目描述
Farmer John 以及他的 \(N(1 \le N \le 2,500)\) 头奶牛打算过一条河,但他们所有的渡河工具,仅仅是一个木筏。由于奶牛不会划船,在整个渡河过程中,FJ 必须始终在木筏上。
在这个基础上,木筏上的奶牛数目每增加 1,FJ 把木筏划到对岸就得花更多的时间。
当 \(FJ\) 一个人坐在木筏上,他把木筏划到对岸需要 \(M(1 \le M \le 1000)\) 分钟。
当木筏搭载的奶牛数从 \(i-1\) 增加到 \(i\) 时,FJ 得多花 \(M_i(1 \le M_i \le 1000)\) 分钟才能把木筏划过河(也就是,船上有 1 头奶牛时,FJ 得花 \(M+M_1\) 分钟渡河;船上有 2 头奶牛时,时间就变成 \(M+M_1+M_2\) 分钟。后面的依此类推)。
那么,FJ 最少要花多少时间,才能把所有奶牛带到对岸呢?
当然,这个时间得包括 FJ 一个人把木筏从对岸划回来接下一批的奶牛的时间。
输入格式
第 1 行:2 个用空格隔开的整数:\(N\) 和 \(M\)。
第 \(2 \dots N+1\) 行:第 \(i+1\) 行为 1 个整数:\(M_i\)。
分析过程
1、状态:
\(\boldsymbol{dp(i)}\):把前 \(i\) 头奶牛全部运到对岸的最少总时间(含返程时间)。
2、分解问题:
考虑最后一组运 \(j\) 头奶牛过河。
在把最后 \(j\) 头奶牛送过去之前,前 \(i-j\) 头奶牛已经全部在对岸了,此时 FJ 也在对岸。因此:
- 先让 FJ 一个人划船回来(耗时 \(M\));
- 再载上 \(j\) 头奶牛过去(耗时 \(M + \sum_{k=1}^{j} M_k\))。
所以转移方程为:
即:
3、边界:
没有奶牛时,不需要渡河:
\(dp(0) = 0\)
4、总结 dp 公式:
💡 对比奶牛渡河 1:本题只是多了 FJ 划船返回的时间(除了最后一次不用返回)。如果"最后一次"也考虑进去,则公式中的 \(2M\) 在最后一趟只需要算 \(M\),但实际实现中通常把 \(dp(N)\) 的最后一趟单独处理,或在状态定义中做区分。
【问题 5】P1968 美元汇率
题目描述
在以后的若干天里戴维将学习美元与德国马克的汇率。编写程序帮助戴维何时应买或卖马克或美元,使他从 100 美元开始,最后能获得最高可能的价值。
输入格式
输入文件的第一行是一个自然数 \(N,\ 1 \le N \le 100\),表示戴维学习汇率的天数。
接下来的 \(N\) 行中每行是一个自然数 \(A,\ 1 \le A \le 1000\)。
第 \(i+1\) 行的 \(A\) 表示预先知道的第 \(i+1\) 天的平均汇率,在这一天中,戴维既能用 100 美元买 \(A\) 马克也能用 \(A\) 马克购买 100 美元。
输出格式
输出文件的第一行也是唯一的一行输出要求的钱数(单位为美元,保留两位小数)。
注意:考虑到实数算术运算中进位的误差,结果在正确结果 \(0.05\) 美元范围内的被认为是正确的,戴维必须在最后一天结束之前将他的钱都换成美元。
输入输出样例
输入
5
400
300
500
300
250
输出
266.67
说明 / 提示
样例解释
- Day 1 … changing 100.0000 美元 = 400.0000 马克
- Day 2 … changing 400.0000 马克 = 133.3333 美元
- Day 3 … changing 133.3333 美元 = 666.6666 马克
- Day 5 … changing 666.6666 马克 = 266.6666 美元
分析过程
1、状态:
定义两种状态,表示第 \(i\) 天结束时的最大资产:
- \(\boldsymbol{dp1(i)}\):第 \(i\) 天结束时,手里全是美元的最大金额。
- \(\boldsymbol{dp2(i)}\):第 \(i\) 天结束时,手里全是马克的最大金额。
2、分解问题:
第 \(i\) 天的汇率为 \(A_i\)(100 美元 = \(A_i\) 马克,即 1 美元 = \(A_i / 100\) 马克)。
考虑第 \(i\) 天结束时手里是美元的情况(dp1[i]),有两种来源:
- 第 \(i-1\) 天手里就是美元,今天不操作,继续持有美元;
- 第 \(i-1\) 天手里是马克,今天把马克换成美元。
同理,第 \(i\) 天结束时手里是马克的情况(dp2[i]):
- 第 \(i-1\) 天手里就是马克,今天不操作;
- 第 \(i-1\) 天手里是美元,今天把美元换成马克。
3、边界:
初始时(第 0 天),戴维有 100 美元,没有马克:
\(dp1(0) = 100.0\)
\(dp2(0) = 0.0\)
4、总结 dp 公式:
最终答案为 \(dp1(N)\),保留两位小数。

浙公网安备 33010602011771号