使用动态规划法求解0/1背包问题
使用上述方法尝试解此题(上一篇总结中):
dp[i][r]:
i代表可选物品{1,2,3,4…i}
r代表背包的剩余容积; w代表重量,W代表背包最大容量
整个dp[i][r]代表在可选物品中选出不超重物品的最大价值。
此问题中w1-w5{2,2,6,5,4}
通过打表可以找到上述规律,可通过此规律完成动态转换方程:
dp[i][r] = max(dp[i-1][r],dp[i-1][r-w[i]]+v[i])
如果硬要掰理由,那么方程含义应为:
此行此列最大价值为上一行此列最大价值与(上行-wi列最大价值+vi)之间的最大值
翻译一下:
上一行此列最大价值:没有选第i个物品的最大价值
上行-wi列最大价值+vi:没有选第i-1个物品但选了第i个物品的最大价值。
因此,此题解的核心就是对第i个物品(不选/选)所得出的最大价值进行讨论。
不选——0
选——1
因此背包问题又叫0/1背包问题。
上面的各个结果隐式地排除了选择物品i后超重的情况,因为超重在打表的时候就已经被排除了。
使用动态规划法求解最大连续子序列和
求序列-2, 11, -4, 13, -5, -2, 4, 2, -9,中最大连续子序列和
自己先求出几个结果出来,填入到表中,直接找规律就完了
如下:
通过打表,可以找到如下规律
dp[i] = max(a[i],a[i]+dp[i-1])
本题并不难以理解,但值得学习的地方并不是动态规划,而在于空间压缩,
按照所打表,dp[i]的空间复杂度为O(n):将每一个i对应的dp[i]都保存下来。
就本题而言完全没必要用到如此大的空间,事实上可以做到空间复杂度为O(2)
一个用来存储当前更新的dp[i],一个用来保存max。
Java源代码:
使用动态规划法求解最长公共子序列问题
本题为经典动态规划问题,不要将子串和子序列弄混。
Str1长度为M,str2长度为N,生成MxX的动态规划表,从上到下,从左到右计算dp。
dp[i][j]:str1[0..i]与str2[0..j]的最长公共子序列的长度
还是套路,先自己算出几个值出来,填入入到表中,找规律
通过打表后可得如下规律:
dp[i][j]依赖于三个位置,左上,左,上。
且当更新最长公共子序列时:
dp[i][j]=dp[i-1][j-1]+1
其他情况
dp[i][j]=Max(dp[i-1][j],dp[i][j-1])
求子序列时可从表的右下方,只按两个方向(左,上)朝左上方向移动。(注意先向上移动,再向左移动)
如果dp[i][j]大于dp[i-1][]和dp[i][j-1] ,
说明之前在计算dp[i][j]的时候,一定选择了,决策dp[i-1][j-1]+1,
可以确定str1[i]等于str2[j],
并且这个字符属于最长公共子序列,将这个字符放入res,然后继续先向上移动,再向左移动。
一个机器人只能向下和向右移动,每次只能移动一步。设计一个算法求它从(0,0) 移到到(m,n) 有多少条路径
(本题为LeetCode动态规划专题原题——不同路径I)
打表如下:
通过找数学规律,写出状态转换方程:
有以下规律:
dp[i][j]=dp[i-1][j]+dp[i][j-1]
本题同样可以使用空间压缩技巧:
观察发现其实
第0行只需要 第1行第0个元素 就能更新为第1行
第1行只需要 第2行第0个元素 就能更新为第2行
第2行只需要 第3行第0个元素 就能更新为第3行
。。。。。
因此已知第0行和第0列可以将整张表压缩为一行。空间复杂度O(n)
而已知第0行和第0列的元素值为1,因此甚至可以将整表压缩到一个位置上
空间复杂度O(1)(可想而知时间复杂度得多大)
动态规划理解起来的确困难,因为要给数学规律一个合理的解释是非常耗费时间的,即使已知在数学规律的背后一定会有原因,但将题做出来跟理解题目不是一个概念,无论你准备朝哪个方向努力。首要的事就是先将题拿下。