1、动态规划,2009级信科1班 李远韬,动态规划的基本原理,将问题转化为规模更小的问题解决。 动态规划与搜索的区别在于动态规划会将已经解决过的子问题的解保存下来,下次需要时直接调用(以空间换时间),而搜索则会将已经计算过的问题再计算一遍。,状态、阶段与决策,状态:用于描述一个子问题 阶段:按照一定的顺序计算所有子问题 决策:通过决策将一个问题转化为更小的子问题,使用动态规划的两个基本条件,最优子结构:问题的最优解只取决与子问题的最优解,即局部最优推出全局最优 无后效性:问题只依赖于更小的子问题,即能够按一定的顺序计算每个子问题,使得每个子问题的解都只依赖于前面已经计算过的问题的解,一个简单的例子
2、:最长上升子序列,给出一个序列a1,a2,an,找到序列a的子序列a(i1),a(i2),.,a(il),1=i1i2.il=n,a(i1)a(i2).a(il),使得l最大,一个简单的例子:最长上升子序列,状态:fi表示序列a1,a2,.,ai的包含ai的最长的子序列的长度 阶段:按i从小到大划分阶段,即按照i从小到大的顺序计算fi,计算f(i)时只依赖于前面计算过的f值 决策:枚举f(i)对应的子序列a(i1),a(i2),.,a(i(l-1),i中i(l-1)的值,设i(l-1)=j,则问题转化为在a1,a2,.,aj中找最长上升子序列,一个简单的例子:最长上升子序列,状态转移方程:f(
3、i)=maxf(j)+1,(1=ji,ajai)时间复杂度:O(n2),动态规划的两种优化方法,简化状态,减少状态总数减少可行的决策,牛场围栏(fence),有N种木料,长度分别为L1,L2,.,LN,每种木料数量无限,每根木料最多可以削短M米,且只能削去整数米,用这些木料修建围栏,问无法修建的最大围栏的长度,如果这个值为无穷大或者任何长度的围栏都可以修建,输出-1 数据范围:N=100,M=3000,1=Li=3000,简化问题,预处理:将每根木料分别削去0,1,2,.,m,得到m根木料,再统计所有的木料长度,去除重复 问题简化为有m根木料,长度分别为L1,L2,.,Lm(不能削短),问不能
4、拼出的最长围栏的长度(或输出无解) 下面只讨论简化后的问题,牛场围栏(fence),一个很自然的想法是通过动态规划计算出对于每个长度L,能否通过现有的木料拼出,但是长度L是没有限制的,即状态的总数可以达到无限,必须减少状态总数,牛场围栏(fence),如果存在长度为L的木料,注意到如果可以拼出长度为x的围栏,那么长度为x+L,x+2L,x+3L,.,x+kL.,的围栏都可以被拼出,牛场围栏(fence),我们将状态设为f(i),(0=iL)表示最小的整数x,满足x可以被拼出,且x mod L=i,如果x不存在,则f(i)为正无穷 为了减少状态总数,加快速度,我们取L=minL1,L2,.,Lm
5、 如果我们能计算出所有的f(i),则答案ans=maxf(i)-L,ans0时则所有长度的围栏都可以被拼出,牛场围栏(fence),状态转移方程:f(i)=minf(j)+Lk ,(j+Lk) mod L=i) 如何划分阶段?如果按照i从小到大划分阶段,不满足无后效性,牛场围栏(fence),仔细观察状态转移方程 f(i)=minf(j)+Lk ,(j+Lk) mod L=i) 注意到f(0)=0,我们建立一个N个节点的图,以0为源点,对所有满足(j+Lk) mod L=i的点i,j,从i向j连一条长度为Lk的边,则f(i)就等于从0到i的最短路 时间复杂度:O(L2),牛场围栏(fence)
6、,此题中的最短路算法本质上也可以看做是以f(i)的值从小到大划分阶段的动态规划,因为f(i)只能由比f(i)的值小的状态f(j)推出。,小结,在上面一道题中,我们通过分析问题,减少状态总数,成功的解决了此题 下面我们来看一个通过减少决策总数来优化动态规划的例子,序列划分,给出一个正整数序列,a1,a2,aN,将序列分成若干段,每段有一个权值,如将ai,aj划分成一段,则该段权值F=(a(i)+a(i+1)+a(j)*i+T,求一种划分方案,使得每段的权值之和最小 数据范围:1=N=1000000,序列划分,我们可以很容易的得到一个O(N2)的动态规划 设状态为fi,表示序列a1,a2,ai的最
7、优划分方案中每段的权值之和 状态转移方程为fi=min(sumi-sumk)*i+t+fk,其中sumi=a1+a2+ai 但是此题中N的范围可以达到1000000,需要优化算法,序列划分,对于状态fi的两种决策k1,k2(k1k2),我们来分析一下决策k1优于k2的条件 决策k1优于k2等价于 (sumi-sumk1)*i+T+fk1(sumi-sumk2)*i+T+fk2 将上式变形后得 i(fk2-fk1)/(sumk2-sumk1),序列划分,我们设g(k1,k2)=(fk2-fk1)/(sumk2-sumk1),(k1i,序列划分,对于任意三个决策k1g(k2,k3) 情况一:如果g
8、(k2,k3)i,则有g(k1,k2)i,决策k1优于决策k2 所以决策k2无论如何都不可能成为最优决策,序列划分,对于任意两个决策k1,k2(k1i,有g(k1,k2)j,即k1在以后的计算中也不可能成为最优决策,序列划分,我们用一个队列k来维护所有可能成为最优决策的决策 k1k2k3kn,那么k1,k2,kn应该满足:ig(k1,k2)g(k2,k3)g(kn-1,kn) 我们在计算fi的过程中维护此队列,则计算fi时的最优决策即为k1,如何维护队列,(1)加入一个新决策k:如果g(kn-1,kn)g(kn,k),则kn为无用决策,将kn从队列中删除,如此反复直到满足g(kn-1,kn)g(kn,k),将k插入队列尾部 (2)删除决策:如果g(k1,k2)i,则k1在以后的计算中都不会成为最优决策,将k1从队首删除,序列划分,时间复杂度分析: 每次决策时都是直接取队首决策为最优决策,每次决策的时间复杂度为O(1) 由于每个决策最多入队一次,出队一次,所以维护队列的总时间复杂度为O(N) 总时间复杂度:O(N),