动态规划
原理
动态规划先解决子问题,再逐步解决大问题。但仅当每个子问题都是离散的,即不依赖于其他子问题时,动态规划才管用
比较方法
可以使用表格法逐个罗列分析,每个表格中填写子问题最优解
示例
包容量为4磅,商品有三件,吉他($1500),音响($3000),电脑($2000),尽可能装下总和最贵的物品
解题思路
网格的各行为商品,各列为不同容量(1~4磅)的背包。所有这些列你都需要,因为它们将
帮助你计算子背包的价值。
| 1磅 | 2磅 | 3磅 | 4磅 |
吉他(G) | $1500 | $1500 G | $1500 G | $1500 G |
音响(S) | $1500 | $1500 | $1500 | $3000 |
电脑(L) | $1500 | $1500 | $2000 | $3500 |
公式
cell[i][j]=以下两者中较大的那个
- 上一个单元格的值(即cel[i-1][j]的值)
- 当前商品的价值+剩余空间的价值(剩余空间的价值: cell[i-1][j-当前商品的重量])
表格中的行或者列位置变换,不会影响最终结果
动态规划启示
- 动态规划可帮助在给定约束条件下找到最优解
- 在问题可分解为彼此独立且离散的子问题时,就可使用动态规划来解决。
- 每种动态规划解决方案都涉及网格。
- 单元格中的值通常就是你要优化的值。
- 每个单元格都是一个子问题,因此你应考虑如何将问题分成子问题,这有助于找出网格的坐标轴
最长公共子串
费曼算法( Feynman algorithm)。
步骤
(1) 将问题写下来。
(2) 好好思考。
(3) 将答案写下来。
此处为抖机灵(ˉ▽ ̄~) ~~
示例
对比hish与fish或vista哪个的公共子串更长?
- hish和fish
| H | I | S | H |
F | O | O | O | O |
I | O | 1 | O | O |
S | O | O | 2 | O |
H | O | O | O | 3 |
- hish和vista
| V | I | S | T | A |
H | O | O | O | O | O |
I | O | 1 | O | O | O |
S | O | O | 2 | O | O |
H | O | O | O | O | O |
PS: 最终答案并不在最后一个单元格.对于最长公共子串问题,答案为网格中最大的数字
计算方法
- 如果两个字母不同,值为O
- 如果两个字母相同,值为左上角邻居的值加1
伪代码实现
if word_a[i]==word_b[j]:
cell[i][j]=cell[i-1][j-1]+1
else:
cell[i][j]=0
最长公共子序列
定义
最长公共子序列:两个单词中都有的序列包含的字母数
示例
fosh,对比fish、fort?
最长公共子串方法
- fosh vs fort
| F | O | S | H |
F | 1 | O | O | O |
O | O | 2 | O | O |
R | O | O | O | O |
T | O | O | O | O |
- fosh vs fish
| F | O | S | H |
F | 1 | O | O | O |
I | O | O | O | O |
S | O | O | 1 | O |
H | O | O | O | 2 |
结果相同均为2
最长公共子序列方法
- fosh vs fort
| F | O | S | H |
F | 1 | 1 | 1 | 1 |
O | 1 | 2 | 2 | 2 |
R | 1 | 2 | 2 | 2 |
T | 1 | 2 | 2 | 2 |
- fosh vs fish
| F | O | S | H |
F | 1 | 1 | 1 | 1 |
I | 1 | 1 | 1 | 1 |
S | 1 | 1 | 2 | 2 |
H | 1 | 1 | 2 | 3 |
计算方法
- 如果两个字母不同,就选择上方和左方邻居中较大的那个
- 如果两个字母相同,就将当前单元格的值设置为左上方单元格的值加1
伪代码实现
if word_a[i]==word_b[j]:
cell[i][j]=cell[i-1][j-1]+1
else:
cell[i][j]=max(cell[i-1][j],cell[i][j-1])
小结
- 需要在给定约束条件下优化某种指标时,动态规划很有用。
- 问题可分解为离散子问题时,可使用动态规划来解决。
- 每种动态规划解决方案都涉及网格。
- 单元格中的值通常就是你要优化的值。
- 每个单元格都是一个子问题,因此需要考虑如何将问题分解为子问题
- 没有放之四海皆准的计算动态规划解决方案的公式。