您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 项目/工程管理 > 1D1D动态规划优化初步
动态规划经典教材1D/1D动态规划优化初步所谓1D/1D动态规划,指的是状态数为O(n),每一个状态决策量为O(n)的动态规划方程。直接求解的时间复杂度为O(n2),但是,绝大多数这样的方程通过合理的组织与优化都是可以优化到O(nlogn)乃至O(n)的时间复杂度的。这里就想讲一讲我对一些比较初步的经典的优化方法的认识。本文中不想进行过多的证明与推导,主要想说明经典模型的建立、转化与求解方法。由于本人认识与水平相当有限,如果出现什么错误与疏漏,还请大牛多多指正。另外,也希望大牛们更多地向我们介绍一下有关动态规划优化的更深入的东西。本文中使用两种方式表示一个函数:f(x)与f[x],用方括号表示的函数值可以在规划之前全部算出(常量),而用圆括号表示的函数值必须在规划过程中计算得到(变量)。无论是什么函数值一经确定,在以后的计算中就不会更改。经典模型一:11()min{()[,]}xifxfiwix相信这个方程大家一定是不陌生的。另外,肯定也知道一个关于决策单调性的性质:假如用k(x)表示状态x取到最优值时的决策,则决策单调性表述为:,()()ijkikj,当且仅当:,[,][1,1][1,][,1]ijwijwijwijwij,对于这个性质的证明读者可以在任意一篇讲述四边形不等式的文章中找到,所以这里不再重复。而且,从实战的角度来看,我们甚至都不需要验证w函数的这个性质,最经济也是最可靠的方法是写一个朴素算法打出决策表来观察(反正你总还是要对拍)。当然,有的时候题目要求你做一点准备工作,去掉一些明显不可能的决策,然后在应用决策单调性。这是上述性质也许会有点用处。正如前文中所述,我们关注的重点是怎样实现决策单调性。有了决策单调性,怎样高效地实现它呢?很容易想到在枚举决策的时候,不需要从1开始,只要从k(x-1)开始就可以了,但这只能降低常数,不可能起到实质性的优化。另一种想法是从k(x-1)开始枚举决策更新f(x),一旦发现决策u不如决策u+1来得好,就停止决策过程,选取决策u作为f(x)的最终决策。这样时间是很大提高了,但可惜是不正确的。决策单调性并没有保证f(j)+w[j,x]有什么好的性质,所以这样做肯定是不对的。刚才我们总是沿着“f(x)的最优决策是什么”这个思路进行思考,下面我们换一个角度,思考对于一个已经计算出来的状态f(j),“f(j)能够更新的状态有哪些”。这样,每一步过程中某些状态的决策可能不是最优的,但是当算法结束的时候所有状态对应的决策一定是最优的。一开始,只有f(1)的函数值被计算出来,于是所有状态的当前最优决策都是1。111111111111111111111111111111111111111111111111111111111111111现在,显然f(2)的值已经确定了:它的最有决策只能是1。我们用决策2来更新这个决策表。由于决策单调性,我们知道新的决策表只能有这样的形式:动态规划经典教材111111111111111111111111111111222222222222222222222222222222这意味着我们可以使用二分法来查找“转折点”,因为如果在一个点x上,如果决策2更好,则所有比x大的状态都是决策2更好;如果x上决策1更好,则所有比x小的状态都是决策1更好。现在决策1和决策2都已经更新完毕,则f(3)业已确定,现在用决策3来更新所有状态。根据决策单调性,现在的决策表只能有以下2种类型:111111111111111111111111111111111222222222222222222333333333331111111111111111111111111333333333333333333333333333333333333而这样的决策表示绝对不会出现的:111111111111333333333333333333322222222222222222222222222222,不可能。那么,我们的更新算法就是:1、考察决策2的区间[b,e]的b点上是否决策3更优,如果是,则全部抛弃决策2,将此区间划归决策3;如果否,则在决策2的区间[b,e]中二分查找转折点。2、如果第1问的回答是“是”,则用同样的方法考察决策1。推演到这一步,相信决策单调性的实现算法已经明了了:使用一个栈来维护数据,占中的每一个元素保存一个决策的起始位置与终了位置,显然这些位置相互连接且依次递增。当插入一个新的决策时,从后到前扫描栈,对于每一个老决策来说,做这样两件事:1、如果在老决策的起点处还是新决策更好,则退栈,全额抛弃老决策,将其区间合并至新决策中,继续扫描下一个决策。2、如果在老决策的起点处是老决策好,则转折点必然在这个老决策的区间中;二分查找之,然后新决策进栈,结束。由于一个决策出栈之后再也不会进入,所以均摊时间为O(1),但是由于二分查找的存在,所以整个算法的时间复杂度为O(nlogn)。下面我们来看两个例题。例题1:玩具装箱。题目来源:湖南省选2008。题目大意:有n个玩具需要装箱,每个玩具的长度为c[i],规定在装箱的时候,必须严格按照给出的顺序进行,并且同一个箱子中任意两个玩具之间必须且只能间隔一个单位长度,换句话说,如果要在一个箱子中装编号为i~j的玩具,则箱子的长度必须且只能是[]jkiljick,规定每一个长度为l的箱子的费用是2()PlL,其中L是给定的一个常数。现在要求你使用最少的代价将所有玩具装箱,箱子的个数无关紧要。分析:本题可以很轻松地列出一个1D1D的动态规划方程:11()min{()[1,]}xifxfiwix,其中2[,]([])jkiwijjickL。不难验证这个方程式满足决策单调性的,于是我们可以直接套用上文中的方法进行优化,时间复杂度为O(nlogn)。动态规划经典教材例题2:土地购买题目来源:USACOMonthly,March,2008,Gold题目大意:有N块土地需要购买,每块土地都是长方形的,有特定的长与宽。你可以一次性购买一组土地,价格是这组土地中长的最大值乘以宽的最大值。比方说一块5*3的土地和一块2*9的土地在一起购买的价格就是9*3。显然,怎样分组购买土地是一门学问,你的任务就是设计一种方案用最少的钱买下所有的土地。分析:将所有土地按照长度降序排列,依次检索,则当前土地的长度必然在上一块土地之内,我们只需要考虑宽度就可以了。而在宽度的问题上,当前土地的行为只能是这样:和前面若干块土地绑定;同时这些绑定的土地和他们前后的土地分离。这样很容易得出状态转移方程:)}(]1[*])[max{(min)(110kfkliwnfnkink这个方程还不能满足决策单调性,下面我们试图再做一下简化。如果将每一个土地的尺寸看成是一个二维坐标的话,(如下图)其中不难看出,红色点完全可以忽略,这些点(x,y)必然满足一个性质:存在点(x’,y’)同时满足x’=x且y’=y,这样它就能被一个组完全覆盖。这些被忽略的点可以通过一次线形的扫描得出。下面,我们着重来看一下不能被忽略的这些点,它们的排布方式必然是单调减。因此状态转移方程可以写成这个样子:)}(]1[*][{min)(10kfkynxnfnk这个转移方程就是标准的决策单调性了,读者可以通过w函数的性质直接证明它。然后,就用上文中的方法在O(nlogn)时间内求解。以上两个例子都是决策单调性的直接应用。其中第二个例子稍微复杂一些,如果不忽略那些“肯定无用”的决策,不对数据进行有序化,则方程是不满足决策单调性的。这也就提醒我们在做这一类题目的时候不能钻牛角尖死做,还得灵活一点。另外,决策单调性提供的只是O(nlogn)的算法,事实上上面两个例题的最佳算法都是O(n)的,在后文中我们将详细介绍另外一种经典模型,并且试图将这两个规划方程通过数学变换转向另一个模型。动态规划经典教材======================================================================下面我们来看一类特殊的w函数:,[,][,][,]ijkwijwjkwik,显然,这一类函数都是满足决策单调性的。但是不同的是,由于这一类函数的特殊性,他们可以用一种更加简洁也更加有借鉴意义的方法解决。由于w函数满足,[,][,][,]ijkwijwjkwik,我们总是可以找到一个特定的一元函数w’[x],使得,[,]'[]'[]ijwijwjwx,这样,假设状态f(x)的某一个决策是k,有:()()[,]()'[]'[]()'[]'[1],fxfkwkxfkwxwkgkwxw,其中()()[1,]gkfkwk。这样我们发现:一旦f(k)被确定,相应地g(k)也被确定,更加关键的是,无论k值如何,w’[x]-w’[1]总是一个常数。换句话说,我们可以把方程写成下述形式:11()min{()}[1,]xkfxgkwx。不难发现这个方程是无聊的,因为1min{()}xkgk我们可以用一个变量“打擂台”直接存储;但是,如果在k的下界上加上一个限制,那这个方程就不是很无聊了。于是,我们就得到了另一个经典模型。经典模型二:1[]()min{()}[]xkbxfxgkwx,其中,b[x]随x不降。这个方程怎样求解呢?我们注意到这样一个性质:如果存在两个数j,k,使得j=k,而且g(k)=g(j),则决策j是毫无用处的。因为根据b[x]单调的特性,如果j可以作为合法决策,那么k一定可以作为合法决策,又因为k比j要优,(注意:在这个经典模型中,“优”是绝对的,是与当前正在计算的状态无关的),所以说,如果把待决策表中的决策按照k排序的话,则g(k)必然是不降的。这样,就引导我们使用一个单调队列来维护决策表。对于每一个状态f(x)来说,计算过程分为以下几步:1、队首元素出队,直到队首元素在给定的范围中。2、此时,队首元素就是状态f(x)的最优决策,3、计算g(x),并将其插入到单调队列的尾部,同时维持队列的单调性(不断地出队,直到队列单调为止)。重复上述步骤直到所有的函数值均被计算出来。不难看出这样的算法均摊时间复杂度是O(1)的。下面我们来看几个例题。例题3:TheSoundofSilence题目来源:BalticOlympiadinInformatics2007题目大意:给出一个N项的数列,如果对于一个连续的长度为M的片段来说,片段内所有数中最大值与最小值的差不超过一个给定的常数C,则我们称这样的片段是一个合法的片段。编程求出所有的合法片段的起始位置。动态规划经典教材分析:本题不难看出可以分解为两个子问题:求所有片段的最大值以及求所有片段的最小值。而这两个任务实际上是一样的,所以我们只需要求取所有的连续M个数的片段中的最小值。这个任务有很多很多种对数级算法,其中用堆或者用静态最优二叉树都可以做到O(nlogm),但是这题的O(n)算法还是不那么好想的。事实上,如果用g[x]表示数列中第x个数的值,用f(x)表示以x作为结尾的有M个数的连续片段的话,显然有:1()min{[]}xixmfxgi,直接吻合经典模型二。套用算法,就可以在O(n)的时间内解决问题。(当然,本题还有一种别致的“窗口”算法,也漂亮地在O(n)的时间内解决了问题,详细可以看官方的解题报告。这里引入本题的主要目的是在于佐证上文中讨论到的经典模型二)例题4:Islands题目来源:IOI2008题目大意:给出一个具有N个顶点的无向加权图,同时这个图中有且恰有N条边。现在,对于这个图中的每一个连通分量,求出其最长路径(权值和最大,一个节点在路径上最多只能出现一次)。分析:当然,这个问题更多的是一个图论题。但是在最后关键问题的处理上还是可以看到经典模型二的影子。首先,用BFS找出所有连通分量。然后,对于一个连通分量来说,由于点数与边数相同,因此必然构成基环+外向树的结构。我们可以找出基环
本文标题:1D1D动态规划优化初步
链接地址:https://www.777doc.com/doc-4366582 .html