动态规划
最近在看算法部分的内容,总结一下。动态规划应用于子问题重叠问题,子问题有公共的子子问题。通常用来求解最优化问题,这样的解可能不止一个。动态规划需要有最优子结构性质和子问题重叠性质。如无权最短路径和无权最长路径,无权最长路径没有最优子结构性质。
子问题图,每个顶点唯一对应一个子问题,每条有向边对应子问题的关联,可以用来分析子问题与子问题直接的依赖关系,通常动态规划的运行时间与顶点和边的数量呈线性关系。
重构解,在动态规划的过程中需要保存当前的选择,用来输出对应的解。
书上给了四种例子:
-
钢条切割,分为一个子问题,即切割长度为i的钢条的最优切割方案,每个子问题有O(n)种选择。该问题包含最优子结构,并且在求解过程中存在子问题重叠性质,所以可以使用动态规划。无论是自上而下的递归还是自底向上,时间复杂度都为O(n²)。
-
矩阵链乘法,分为了两个子问题,并且有i,j 两个变量用来表示两边的位置,用k来遍历当前一次的选择,所以时间复杂度为O(n^3)。总共的子问题数为O(n²),相当于矩阵的上三角。
-
最长公共子序列,分为了两个子问题,有i,j两个变量,分别遍历两个序列的长度m,n ,但每个子问题只执行O(1),所以总的时间复杂度为O(mn)。
-
最优二叉树搜索,通过构造一次搜索的期望(包含关键字的代价与伪关键字的代价),求最小的期望。递归通过e[i,j]表示从节点i到j需要的代价,与选择一个根节点r之间的关系得到。直接递归会非常低效,所以使用一个表e[1...n+1 , 0...n]来存储e[i,j]的值。可以看到,该问题分为两个子问题,有两个变量i,j,并且每个子问题有r个(最大为n),所以时间复杂度为O(n^3)。总共的子问题数为O(n²),相当于矩阵的上三角。
贪心算法
每一步都做出当时看起来最佳的选择。
贪心算法通常都是自顶向下的设计,做出一个选择然后求解剩下的子问题。例如活动分配问题,通过动态规划求解为O(n²)个子问题,而贪心算法只有O(n)。
贪心算法有两种特性,贪心选择性质和最优子结构性质,最优子结构与动态规划一样,都是最优解包含子问题的最优解。贪心选择性质,即通过做出局部最优(贪心)来构造全局最优解。书上给了几个例子。
-
0-1背包问题不能用贪心算法求解,因为无法装满背包,空闲空间降低了方案的有效每磅价值。在一个商品装入背包时,需要考虑包含或者不包含,(当前子问题与上一次子问题重叠)需要用动态规划;而分数背包问题可以用贪心算法。
-
找零钱问题中,根据硬币的面值不同,有的可以用贪心算法,而有的不行。例如硬币面值为30,20,1 。如果需要找40元,贪心算法为 1*30+10*1,而最优解为2*20。该问题不符合贪心选择性质。
-
赫夫曼编码,最优前缀码,同样需要证明贪心选择性质和最优子结构性质。证明思路都是通过构造一个最优前缀码的树,然后通过替换最低频率的字符(贪心选择)来实现另一个更优前缀码树,说明贪心选择性质。
总结一下,分治法存在最优子结构性质,但是不存在子问题重叠;动态规划需要最优子结构性质,以及子问题重叠;贪心算法需要贪心选择性质和最优子结构性质。

1434

被折叠的 条评论
为什么被折叠?



