动态规划与贪心算法的区别与联系
来源:互联网 发布:赛事专用软件源码php 编辑:程序博客网 时间:2024/05/21 09:23
走出迷宫的人们,有的是认识路;有的是莽撞碰巧出来的;有的则是一路做着标记出来的;也有的是走遍了整个迷宫。
——证明了的贪心算法、没有证明的贪心算法、动态规划、暴力搜索的区别。
今天来谈谈经典的算法设计思路问题,涉及搜索(Searching),动态规划(DP, Dynamic Programming),贪心算法(GA, Greedy Algorithm)……至于什么回溯法(Backtracking)只能是搜索的方向问题。
经常听人说起:“搜索、动态规划、贪心算法这几种算法云云”,好像这些算法彼此之间并没有交集一样。
非也,它们的渊源大了!
从范畴上来看:
即,所有的贪心算法问题都能用DP求解,更可以归结为一个搜索问题,反之不成立。
从动规到贪心
不管是动态规划还是贪心本质上都是一个搜索,这一点少有人发出疑问的。
然而却时常有人争论某问题是贪心的还是动归的,一个问题是贪心的还是动归的有联系但并不对立。
看一个具体的例子:
食堂里有n个人要在一个队列里排队买饭,每个人花费的时间分别为
比如有三个人,分别用时3,2,5,那么最佳的排序应该是2,3,5,总用时是2 + 5 + 10 = 17,对此,你可以简单地验证一下其他5种的组合来验证这个答案是正确的。
这个问题在暴力搜索算法中需要消耗O(n!)的时间来生成所有的排列并从中获得最小值。
也许我们需要优化一下……正常人略作思考便可以猜出让耗时短的人优先的贪心优化策略。
于是就有了这样一段代码(JavaScript),可以直接在现代浏览器的控制台内使用(推荐Chrome)。
var solve = C => { C.sort(); var sum = 0; C.forEach((e, i) => sum += e * (C.length - i)); return { min: sum, order: C };}solve([3, 2, 5]); // Object {min: 17, order: Array[3]}
这个问题的解空间是C数组的所有排列的集合,解空间的大小显然是O(n!)的,实际上其占用的存储空间是
由于任意顺序的C的所有排列的集合是一样的,因此他们的解空间与解都是一样的,所以我们直接把问题等价地化为经
设前
我们考虑把第i个人插入到前i-1个人的队列中去。
等等,我们是否能证明前i -1个人的最优排列也是前i个人最优排列的子排列(最优子结构的性质是否具备)?可以。假设前i人的最优排列不包含前i-1人的最优排列,则将除第i人外的人调整成前i-1人的序列可以更优,与假设矛盾,因此前i-1人的最优排列一定是前i人最优排列的子排列。
尝试将第i人插在第j人的前面,并考虑带来的影响,便有状态转移方程:
对于
有
即证出
代入可得
由此证明了最佳策略为将最大的第i人放在最后。
后面这个看似O(n)的求和操作也可以事先缓存,按照DP写法这个问题就变成了这样
(除了必要的排序,时空复杂度均已达到最优O(n)):
var solve = C => { C.sort(); var dp = C.map(() => 0); var sum = C.map(e => e); sum.forEach((e, i) => { sum[i] += i > 0? sum[i - 1]: 0; }); dp.forEach((e,i) => { dp[i] = sum[i] + (i > 0? dp[i - 1]: 0); }); return { min: dp[dp.length - 1], order: C, }}
对上面的数学公式再进一步则是:
再按照计数原理得到
因而最后可以直接化为两个向量的数量积:
这似乎已经变为了人们口中的贪心算法,但究竟是从推导的什么地方开始变为具有贪心性质了呢?
回顾一下,当我们证明了
与其将它称为贪婪,我觉得它更是智慧的象征。
多维解空间与不完全贪心
很多时候,问题的解空间并不适合用一维来描述,当解空间在一维以上,比如……还记得经典的0-1背包问题么?那就是一个典型的二维解空间问题。
对于物品
通常我们设前
有状态转移方程:
这个时候我们看到解空间的第一维的策略是可贪心的:再计算
这种优化本质上是贪心的,是不完全的贪心,因为它只在某些维度上进行了贪心。
贪心算法与动态规划的效率区别
从动态规划优化到贪心算法真的提高了算法效率吗?未必。
这取决于动态规划中计算所有可选的策略的代价,如果代价是常数的,那么将其贪心优化并不会带来时间复杂度的下降(本文的两个例子都是如此),该走的解空间还是要走,只是不保存其中的一些值而已,可能会带来空间复杂度的下降。
有趣的是,当计算策略的代价并非常数(如Floyd全局最短路算法)时,往往并不只有一个策略,因而不能贪心优化。
因此,贪心算法不会降低从其对应的动态规划解法的时间复杂度,如果你发现它降低了,那么一定存在更好的解空间建模,更好的动态规划算法。
贪心算法确实可能比其对应的动态规划快不少,因为它的常数可能小得多。
但是,当你试图对同一解空间的不同点进行多次查询时,你会发现贪心可能会得不偿失,在均摊时间上输给不贪心的动态规划。
贪心优化是否失去了什么
贪心在于其抛弃了部分子结构的解。
如顺带要求出方案而不仅仅是最大价值的0-1背包问题,本来使用不优化空间的解法完全能够保留倒推回去的线索,如PAT 1068 Find More Coins 解题报告 所说一般。如果抛弃了动态规划带来的一些解,很有可能在其衍生的问题上得不偿失。
小结
既然已经得出贪心是动规的优化,那么循序渐进地解问题的思路应该先从搜索开始:先对问题的解空间建模,如果得到最优子结构的性质,写出状态转移方程,再看某些维度是否有贪心的优化余地,并且考虑一下,这些优化到底是否值得。
- 动态规划与贪心算法的区别与联系
- 动态规划与贪心算法的区别与联系
- [算法导论] 动态规划与贪心算法的区别与联系
- 动态规划与贪心算法的区别
- 从硬币找零问题:看分治/动态规划/贪心算法的区别与联系
- 【动态规划】【贪心】动态规划与贪心的联系
- 贪心算法与动态规划区别
- 动态规划、分治法与贪心算法的区别
- 动态规划、分治法与贪心算法的区别
- 动态规划、分治法与贪心算法的区别
- 贪心与动态规划的区别
- 动态规划与贪心的区别
- 动态规划以及与贪心的区别
- 动态规划与贪心算法的比较
- 贪心算法与动态规划的比较
- 动态规划与贪心算法
- 动态规划与贪心算法
- 理解动态规划算法与贪心算法区别----找钱问题
- tag文件实现分页
- C/C++,C#,JAVA数组
- Qt学习笔记之系统时间的获取
- AC自动机详解
- LAb3-自行车码表
- 动态规划与贪心算法的区别与联系
- HTML5第9节课堂笔记(初探mui,制作手机归属地查询)
- HDU 5676 ztr loves lucky numbers(dfs+离线)——BestCoder Round #82(div.1 div.2)
- hdu 1039 Easier Done Than Said?
- 1.系统调用的过程
- Light OJ 1031 Easy Game 区间DP
- Summer Training Team Selection (1) Problem F Line Them Up 判断升序降序
- 学习PS基础
- Volley源码解析(一),基本概述