g[0,0,k]=0;
我们来分析上述算法的时间复杂度,上述算法的状态总数为O(n*m*t),每个状态转移的状态数为O
(1),每次状态转移的时间为O
(1),所以总的时间复杂度为O(n*m*t)。
由于n,m,t均不超过20,所以可以满足要求。
[算法优化]
当数据规模较大时,上述算法就无法满足要求,我们来考虑通过改进状态表示提高算法的时间效率。
本题的最优目标是用给定长度的若干张唱片录制尽可能多的歌曲,这实际上等价于在录制给定数量的歌曲时尽可能少地使用唱片。
所谓“尽可能少地使用唱片”,就是指使用的完整的唱片数尽可能少,或是在使用的完整的唱片数相同的情况下,另加的分钟数尽可能少。
分析可知,在这样的最优目标之下,该问题同样具有最优子结构性质,即:
设D在前i首歌中选取j首歌录制的最少唱片使用方案,那么若其中选取了第i首歌,则D-{i}是在前i-1首歌中选取j-1首歌录制的最少唱片使用方案,否则D前i-1首歌中选取j首歌录制的最少唱片使用方案,同样,问题的最优解包含了子问题的最优解。
改进的状态表示描述为:
g[i,j]=(a,b),0≤i≤n,0≤j≤i,0≤a≤m,0≤b≤t,表示在前i首歌曲中选取j首录制所需的最少唱片为:
a张唱片另加b分钟。
由于第i首歌分为发行和不发行两种情况,这样我们可以得到如下的状态转移方程和边界条件:
g[i,j]=min{g[i-1,j],g[i-1,j-1]+long[i]}
其中(a,b)+long[i]=(a’,b’)的计算方法为:
当long[i]≤t-b时:
a’=a;b’=b+long[i];
当long[i]>t-b时:
a’=a+1;b’=long[i];
规划的边界条件:
g[i,0]=(0,0)0≤i≤n
这样题目所求的最大值是:
ans=max{k|g[n,k]≤(m-1,t)}
改进后的算法,状态总数为O(n2),每个状态转移的状态数为O
(1),每次状态转移的时间为O
(1),所以总的时间复杂度为O(n2)。
值得注意的是,算法的空间复杂度也由改进前的O(m*n*t)降至优化后的O(n2)。
(程序及优化前后的运行结果比较见附件)
通过对本题的优化,我们认识到:
应用不同的状态表示方法设计出的动态规划算法的性能也迥然不同。
改进状态表示可以减少状态总数,进而降低算法的时间复杂度。
在降低算法的时间复杂度的同时,也降低了算法的空间复杂度。
因此,减少状态总数在动态规划的优化中占有重要的地位。
2、选择适当的规划方向
动态规划方法的实现中,规划方向的选择主要有两种:
顺推和逆推。
在有些情况下,选取不同的规划方向,程序的时间效率也有所不同。
一般地,若初始状态确定,目标状态不确定,则应考虑采用顺推,反之,若目标状态确定,而初始状态不确定,就应该考虑采用逆推。
那么,若是初始状态和目标状态都已确定,一般情况下顺推和逆推都可以选用,但是,能否考虑选用双向规划呢?
双向搜索的方法已为大家所熟知,它的主要思想是:
在状态空间十分庞大,而初始状态和目标状态又都已确定的情况下,由于扩展的状态量是指数级增长的,于是为了减少状态的规模,分别从初始状态和目标状态两个方向进行扩展,并在两者的交汇处得到问题的解。
上述优化思想能否也应用到动态规划之中呢?
来看下面这个例子。
例二、Divide(Merc`2000)
[问题描述]
有价值分别为1..6的大理石各a[1..6]块,现要将它们分成两部分,使得两部分价值和相等,问是否可以实现。
其中大理石的总数不超过20000。
(英文试题详见附件)
[算法分析]
令S=∑(i*a[i]),若S为奇数,则不可能实现,否则令Mid=S/2,则问题转化为能否从给定的大理石中选取部分大理石,使其价值和为Mid。
这实际上是母函数问题,用动态规划求解也是等价的。
m[i,j],0≤i≤6,0≤j≤Mid,表示能否从价值为1..i的大理石中选出部分大理石,使其价值和为j,若能,则用true表示,否则用false表示。
则状态转移方程为:
m[i,j]=m[i,j]ORm[i-1,j-i*k](0≤k≤a[i])
规划的边界条件为:
m[i,0]=true;0≤i≤6
若m[i,Mid]=true,0≤i≤6,则可以实现题目要求,否则不可能实现。
我们来分析上述算法的时间性能,上述算法中每个状态可能转移的状态数为a[i],每次状态转移的时间为O
(1),而状态总数是所有值为true的状态的总数,实际上就是母函数中项的数目。
[算法优化]
实践发现:
本题在i较小时,由于可选取的大理石的价值品种单一,数量也较少,因此值为true的状态也较少,但随着i的增大,大理石价值品种和数量的增多,值为true的状态也急剧增多,使得规划过程的速度减慢,影响了算法的时间效率。
另一方面,我们注意到我们关心的仅是能否得到价值和为Mid的值为true的状态,那么,我们能否从两个方向分别进行规划,分别求出从价值为1..3的大理石中选出部分大理石所能获得的所有价值和,和从价值为4..6的大理石中选出部分大理石所能获得的所有价值和。
最后通过判断两者中是否存在和为Mid的价值和,由此,可以得出问题的解。
状态转移方程改进为:
当i≤3时:
m[i,j]=m[i,j]ORm[i-1,j-i*k](1≤k≤a[i])
当i>3时:
m[i,j]=m[i,j]ORm[i+1,j-i*k](1≤k≤a[i])
规划的边界条件为:
m[i,0]=true;0≤i≤7
这样,若存在k,使得m[3,k]=true,m[4,Mid-k]=true,则可以实现题目要求,否则无法实现。
(程序及优化前后的运行结果比较见附件)
从上图可以看出双向动态规划与单向动态规划在计算的状态总数上的差异。
回顾本题的优化过程可以发现:
本题的实际背景与双向搜索的背景十分相似,同样有庞大的状态空间,有确定的初始状态和目标状态,状态量都迅速增长,而且可以实现交汇的判断。
因此,由本题的优化过程,我们认识到,双向扩展以减少状态量的方法不仅适用于搜索,同样适用于动态规划。
这种在不同解题方法中,寻找共通的属性,从而借用相同的优化思想,可以使我们不断创造出新的方法。
3.2减少每个状态转移的状态数
在使用动态规划方法解题时,对当前状态的计算都是进行一些决策并引用相应的已经计算过的状态,这个过程称为“状态转移”。
因此,每个状态可能做出的决策数,也就是每个状态可能转移的状态数是决定动态规划算法时间复杂度的一个重要因素。
本节将讨论减少每个状态可能转移的状态数的一些方法。
1、四边形不等式和决策的单调性
例三、石子合并问题(NOI`95)
[问题描述]
在一个操场上摆放着一排n(n≤20)堆石子。
现要将石子有次序地合并成一堆。
规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。
试编程求出将n堆石子合并成一堆的最小得分和最大得分以及相应的合并方案。
[算法分析]
这道题是动态规划的经典应用。
由于最大得分和最小得分是类似的,所以这里仅对最小得分进行讨论。
设n堆石子依次编号为1,2,…..,n。
各堆石子数为d[1..n],则动态规划的状态表示为:
m[i,j],1≤i≤j≤n,表示合并d[i..j]所得到的最小得分,则状态转移方程和边界条件为:
m[i,j]=0i=j
i<j
同时令s[i,j]=k,表示合并的断开位置,便于在计算出最优值后构造出最优解。
上式中
的计算,可在预处理时计算
,i=1..n;t[0]=0,则:
上述算法的状态总数为O(n2),每个状态转移的状态数为O(n),每次状态转移的时间为O
(1),所以总的时间复杂度为O(n3)。
[算法优化]
当函数w[i,j]满足
时,称w满足四边形不等式[2]。
当函数w[i,j]满足w[i’,j]≤w[i,j’]
时称w关于区间包含关系单调。
在石子归并问题中,令w[i,j]=
,则w[i,j]满足四边形不等式,同时由d[i]≥0,t[i]≥0可知w[i,j]满足单调性。
m[i,j]=0i=j
i对于满足四边形不等式的单调函数w,可推知由递推式①定义的函数m[i,j]也满足四边形不等式,即
。
这一性质可用数学归纳法证明如下:
我们对四边形不等式中“长度”l=j’-i进行归纳:
当i=i’或j=j’时,不等式显然成立。
由此可知,当l≤1时,函数m满足四边形不等式。
下面分两种情形进行归纳证明:
情形1:
i
在这种情形下,四边形不等式简化为如下的反三角不等式:
m[i,j]+m[j,j’]≤m[i,j’],设k=max{p|m[i,j’]=m[i,p-1]+m[p,j’]+w[i,j’]},再分两种情形k≤j或k>j。
下面只讨论k≤j,k>j的情况是类似的。
情形1.1:
k≤j,此时:
情形2:
i
设y=max{p|m[i’,j]=m[i’,p-1]+m[p,j]+w[i’,j]}
z=max{p|m[i,j’]=m[i,p-1]+m[p,j’]+w[i,j’]}
仍需再分两种情形讨论,即z≤y或z>y。
下面只讨论z≤y,z>y的情况是类似的。
由i综上所述,m[i,j]满足四边形不等式。
令s[i,j]=max{k|m[i,j]=m[i,k-1]+m[k,j]+w[i,j]}
由函数m[i,j]满足四边形不等式可以推出函数s[i,j]的单调性,即
s[i,j]≤s[i,j+1]≤s[i+1,j+1],i≤j
当i=j时,单调性显然成立。
因此下面只讨论i由于对称性,只要证明s[i,j]≤s[i,j+1]。
令mk[i,j]=m[i,k-1]+m[k,j]+w[i,j]。
要证明s[i,j]≤s[i,j+1],只要证明对于所有imk’[i,j+1]≤mk[i,j+1]。
事实上,我们可以证明一个更强的不等式
mk[i,j]-mk’[i,j]≤mk[i,j+1]-mk’[i,j+1]
也就是:
mk[i,j]+mk’[i,j+1]≤mk[i,j+1]+mk’[i,j]
利用递推定义式将其展开整理可得:
m[k,j]+m[k’,j+1]≤m[k’,j]+m[k,j+1],这正是k≤k’≤j综上所述,当w满足四边形不等式时,函数s[i,j]具有单调性。
于是,我们利用s[i,j]的单调性,得到优化的状态转移方程为:
m[i,j]=0i=j
i用类似的方法可以证明,对于最大得分问题,也可采用同样的优化方法。
改进后的状态转移方程所需的计算时间为
(程序及优化前后的运行结果比较见附件)
上述方法利用四边形不等式推出最优决策的单调性,从而减少每个状态转移的状态数,降低算法的时间复杂度。
上述方法是具有普遍性的。
对于状态转移方程与①式类似,且w[i,j]满足四边形不等式的动态规划问题,都可以采用相同的优化方法,如最优二叉排序树(NOI`96)等。
下面再举一例。
例四、邮局(IOI`2000)
[问题描述]
按照递增顺序给出一条直线上坐标互不相同的n个村庄,要求从中选择p个村庄建立邮局,每个村庄使用离它最近的那个邮局,使得所有村庄到各自所使用的邮局的距离总和最小。
试编程计算最小距离和,以及邮局建立方案。
[算法分析]
本题也是一道动态规划问题,详细分析请看文本附件(邮局解题报告)。
将n个村庄按坐标递增依次编号为1,2,……,n,各个邮局的坐标为d[1..n],状态表示描述为:
m[i,j]表示在前j个村庄建立i个邮局的最小距离和。
所以,m[p,n]即为问题的解,且状态转移方程和边界条件为:
m[1,j]=w[1,j]
i≤j
其中w[i,j]表示在d[i..j]之间建立一个邮局的最小距离和,可以证明,当仅建立一个邮局时,最优解出现在中位数,即设建立邮局的村庄为k,则
,于是,我们有:
,
同时,令s[i,j]=k,记录使用前i-1个邮局的村庄数,便于在算出最小距离和之后构造最优建立方案。
上述算法中w[i,j]可通过O(n)时间的预处理,在O
(1)的时间内算出,所以,该算法的状态总数为O(n*p),每个状态转移的状态数为O(n),每次状态转移的时间为O
(1),该算法总的时间复杂度为O(p*n2)。
[算法优化]
本题的状态转移方程与①式十分相似,因此我们猜想其决策是否也满足单调性,即
s[i-1,j]≤s[i,j]≤s[i,j+1]
首先,我们来证明函数w满足四边形不等式,即:
设
,
,下面分为两种情形,z≤y或z>y,下面仅讨论z≤y,z>y的情况是类似的。
由i≤z≤y≤j有:
接着,我们用数学归纳法证明函数m也满足四边形不等式。
对四边形不等式中“长度”l=j’-i进行归纳:
当i=i’或j=j’时,不等式显然成立。
由此可知,当l≤1时,函数m满足四边形不等式。
下面分两种情形进行归纳证明:
情形1:
i
设k=max{p|m[i,j’]=m[i,p-1]+m[p,j’]+w[i,j’]},再分两种情形k≤j或k>j。
下面只讨论k≤j,k>j的情况是类似的。
情形2:
i
设y=max{p|m[i’,j]=m[i’-1,p]+w[p+1,j]}
z=max{p|m[i,j’]=m[i-1,p]+w[p+1,j’]}
仍需再分两种情形讨论,即z≤y或z>y。
情形2.1,当z≤y情形2.2,当i-1
最后,我们证明决策s[i,j]满足单调性。
为讨论方便,令mk[i,j]=m[i-1,k]+w[k+1,j];
我们先来证明s[i-1,j]≤s[i,j],只要证明对于所有i≤kmk’[i,j]≤mk[i,j]。
类似地,我们可以证明一个更强的不等式
mk[i-1,j]-mk’[i-1,j]≤mk[i,j]-mk’[i,j]
也就是:
mk[i-1,j]+mk’[i,j]≤mk[i,j]+mk’[i-1,j]
利用递推定义式展开整理的:
m[i-2,k]+m[i-1,k’]≤m[i-1,k]+m[i-2,k’],这就是i-2我们再来证明s[i,j]≤s[i,j+1],与上文类似,设kmk[i,j]-mk’[i,j]≤mk[i,j+1]-mk’[i,j+1]
也就是:
mk[i,j]+mk’[i,j+1]≤mk[i,j+1]+mk’[i,j]
利用递推定义式展开整理的:
w[k+1,j]+w[k’+1,j+1]≤w[k+1,j+1]+w[k’+1,j],这就是k+1综上所述,该问题的决策s[i,j]具有单调性,于是优化后的状态转移方程为:
m[1,j]=w[1,j]
i≤j
s[i,j]=k
同上文所述,优化后的算法时间复杂度为O(n*p)。
(程序及优化前后的运行结果比较见附件)
四边形不等式优化的实质是对结果的充分利用。
它通过分析状态值之间的特殊关系,推出了最优决策的单调性,从而在计算当前状态时,利用已经计算过的状态所做出的最优决策,减少了当前的决策量。
这就启发我们,在应用动态规划解题时,不仅可以实现状态值的充分利用,也可以实现最优决策的充分利用。
这实际上是从另一个角度实现了“减少冗余”。
2、决策量的优化
通过分析问题最优解所具备的性质,从而缩小有可能产生最优解的决策集合,也是减少每个状态可能转移的状态数的一种方法。
大家所熟悉的NOI`96中的添加号问题,正是从“所得的和最小”这一原则出发,仅在等分点的附近添加号,从而大大减少了每个状态转移的状态数,降低了算法的时间复杂度。
让我们在再来看一例。
例五、石子归并的最大得分问题
[问题描述]
见例三,本例只考虑最大得分问题。
[算法分析]
设n堆石子依次编号为1,2,…..,n。
各堆石子数为d[1..n],则动态规划的状态表示为:
m[i,j],1≤i≤j≤n,表示合并d[i..j]所得到的最大得分,则状态转移方程和边界条件为:
m[i,j]=0i=j
i<j
同时令s[i,j]=k,表示合并的断开位置,便于在计算出最优值后构造出最优解。
该算法的时间复杂度为O(n3)。
[算法优化]
仔细分析问题,可以发现:
s[i,j]要么等于i+1,要么等于j,即:
证明可以采用反证法,设使m[i,j]达到最大值的断开位置为p,且i+1
,
,下面分为2种情形讨论。
情形1、y≥z
由p((a[i]…a[p-1])((a[p]...a[k-1])(a[k]..a[j])))
相应的得分为:
…………①
下面考虑另一种合并方案s’[i,j]=k,s’[i,k]=p,表示为:
(((a[i]…a[p-1])(a[p]...a[k-1]))(a[k]..a[j]))
相应的得分为:
…………②
由y≥z可得,T情形2、y于是,状态转移方程优化为:
m[i,j]=0i=j
i<j
优化后每个状态转移的状态数减少为O
(1),算法总的时间复杂度也降为O(n2)。
(程序及优化前后的运行结果比较见附件)
本题的优化过程是通过对问题最优解性质的分析,找出最优决策必须满足的必要条件,这与搜索中的最优性剪枝的思想十分类似,由此我们再次看到了相同的优化思想应用于不同的算法设计方法。
同时,我们也认识到:
动态规划的优化必须建立在全面细致分析问题的基础上,只有深入分析问题的属性,挖掘问题的实质,才能实现算法的优化。
3、合理组织状态
在动态规划求解的过程中,需要不断地引用已经计算过的状态。
因此,合理地组织已经计算出的状态有利于提高动态规划的时间效率。
例六、求最长单调上升子序列
[问题描述]
给出一个由n个数组成的序列x[1..n],找出它的最长单调上升子序列。
即求最大的m和a1,a2……,am,使得a1[算法分析]
这也是一道动态规划的经典应用。
动态规划的状态表示描述为:
m[i],1≤i≤n,表示以x[i]结尾的最长上升子序列的长度,则问题的解为max{m[i],1≤i≤n},状态转移方程和边界条件为:
m[i]=1+max{0,m[k]|x[k]同时当m[i]>1时,令p[i]=k,表示最优决策,以便在计算出最优值后构造最长单调上升子序列。
上述算法的状态总数为O(n),每个状态转移的状态数最多为O(n),每次状态转移的时间为O
(1),所以算法总的时间复杂度为O(n2)。
[算法优化]
我们先来