动态规划.docx

上传人:b****8 文档编号:11454512 上传时间:2023-03-01 格式:DOCX 页数:15 大小:100.31KB
下载 相关 举报
动态规划.docx_第1页
第1页 / 共15页
动态规划.docx_第2页
第2页 / 共15页
动态规划.docx_第3页
第3页 / 共15页
动态规划.docx_第4页
第4页 / 共15页
动态规划.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

动态规划.docx

《动态规划.docx》由会员分享,可在线阅读,更多相关《动态规划.docx(15页珍藏版)》请在冰豆网上搜索。

动态规划.docx

动态规划

§1动态规划的本质

动态规划是在本世纪50年代初,为了解决一类多阶段决策问题而诞生的。

那么,什么样的问题被称作多阶段决策问题呢?

§1.1多阶段决策问题

说到多阶段决策问题,人们很容易举出下面这个例子。

[例1]

多段图中的最短路径问题:

在下图中找出从A1到D1的最短路径。

仔细观察这个图不难发现,它有一个特点。

我们将图中的点分为四类(图中的A、B、C、D),那么图中所有的边都处于相邻的两类点之间,并且都从前一类点指向后一类点。

这样,图中的边就被分成了三类(AB、BC、CD)。

我们需要从每一类中选出一条边来,组成从A1到D1的一条路径,并且这条路径是所有这样的路径中的最短者。

从上面的这个例子中,我们可以大概地了解到什么是多阶段决策问题。

更精确的定义如下:

多阶段决策过程,是指这样的一类特殊的活动过程,问题可以按时间顺序分解成若干相互联系的阶段,在每一个阶段都要做出决策,全部过程的决策是一个决策序列[1]。

要使整个活动的总体效果达到最优的问题,称为多阶段决策问题。

从上述的定义中,我们可以明显地看出,这类问题有两个要素。

一个是阶段,一个是决策。

§1.2阶段与状态

阶段:

将所给问题的过程,按时间或空间特征分解成若干相互联系的阶段,以便按次序去求每阶段的解。

常用字母k表示阶段变量。

[1]

阶段是问题的属性。

多阶段决策问题中通常存在着若干个阶段,如上面的例子,就有A、B、C、D这四个阶段。

在一般情况下,阶段是和时间有关的;但是在很多问题(我的感觉,特别是信息学问题)中,阶段和时间是无关的。

从阶段的定义中,可以看出阶段的两个特点,一是“相互联系”,二是“次序”。

阶段之间是怎样相互联系的?

就是通过状态和状态转移。

状态:

各阶段开始时的客观条件叫做状态。

描述各阶段状态的变量称为状态变量,常用sk表示第k阶段的状态变量,状态变量sk的取值集合称为状态集合,用Sk表示。

[1]

状态是阶段的属性。

每个阶段通常包含若干个状态,用以描述问题发展到这个阶段时所处在的一种客观情况。

在上面的例子中,行人从出发点A1走过两个阶段之后,可能出现的情况有三种,即处于C1、C2或C3点。

那么第三个阶段就有三个状态S3={C1,C2,C3}。

每个阶段的状态都是由以前阶段的状态以某种方式“变化”而来,这种“变化”称为状态转移(暂不定义)。

上例中C3点可以从B1点过来,也可以从B2点过来,从阶段2的B1或B2状态走到阶段3的C3状态就是状态转移。

状态转移是导出状态的途径,也是联系各阶段的途径。

说到这里,可以提出应用动态规划的一个重要条件。

那就是将各阶段按照一定的次序排列好之后,对于某个给定的阶段状态,它以前各阶段的状态无法直接影响它未来的发展,而只能通过当前的这个状态。

换句话说,每个状态都是“过去历史的一个完整总结[1]”。

这就是无后效性。

对这个性质,下文还将会有解释。

§1.3决策和策略

上面的阶段与状态只是多阶段决策问题的一个方面的要素,下面是另一个方面的要素——决策。

决策:

当各段的状态取定以后,就可以做出不同的决定,从而确定下一阶段的状态,这种决定称为决策。

表示决策的变量,称为决策变量,常用uk(sk)表示第k阶段当状态为sk时的决策变量。

在实际问题中,决策变量的取值往往限制在一定范围内,我们称此范围为允许决策集合。

常用Dk(sk)表示第k阶段从状态sk出发的允许决策集合。

显然有uk(sk)Dk(sk)。

[1]

决策是问题的解的属性。

决策的目的就是“确定下一阶段的状态”,还是回到上例,从阶段2的B1状态出发有三条路,也就是三个决策,分别导向阶段3的C1、C2、C3三个状态,即D2(B1)={C1,C2,C3}。

有了决策,我们可以定义状态转移:

动态规划中本阶段的状态往往是上一阶段和上一阶段的决策结果,由第k段的状态sk和本阶段的决策uk确定第k+1段的状态sk+1的过程叫状态转移。

状态转移规律的形式化表示sk+1=Tk(sk,uk)称为状态转移方程。

这样看来,似乎决策和状态转移有着某种联系。

我的理解,状态转移是决策的目的,决策是状态转移的途径。

各段决策确定后,整个问题的决策序列就构成一个策略,用p1,n={u1(s1),u2(s2),…,un(sn)}表示。

对每个实际问题,可供选择的策略有一定范围,称为允许策略集合,记作P1,n,使整个问题达到最有效果的策略就是最优策略。

[1]

说到这里,又可以提出运用动态规划的一个前提。

即这个过程的最优策略应具有这样的性质:

无论初始状态及初始决策如何,对于先前决策所形成的状态而言,其以后的所有决策应构成最优策略[1]。

这就是最优化原理。

简言之,就是“最优策略的子策略也是最优策略”。

§1.4最优化原理与无后效性

这里,我把最优化原理定位在“运用动态规划的前提”。

这是因为,是否符合最优化原理是一个问题的本质特征。

对于不满足最优化原理的一个多阶段决策问题,整体上的最优策略p1,n同任何一个阶段k上的决策uk或任何一组阶段k1…k2上的子策略pk1,k2都不存在任何关系。

如果要对这样的问题动态规划的话,我们从一开始所作的划分阶段等努力都将是徒劳的。

而我把无后效性定位在“应用动态规划的条件”,是因为动态规划是按次序去求每阶段的解,如果一个问题有后效性,那么这样的次序便是不合理的。

但是,我们可以通过重新划分阶段,重新选定状态,或者增加状态变量的个数等手段,来是问题满足无后效性这个条件。

说到底,还是要确定一个“序”。

在信息学的多阶段决策问题中,绝大部分都是能够满足最优化原理的,但它们往往会在后效性这一点上来设置障碍。

所以在解题过程中,我们会特别关心“序”。

对于有序的问题,就会考虑到动态规划;对于无序的问题,也会想方设法来使其有序。

§1.5最优指标函数和规划方程

最优指标函数:

用于衡量所选定策略优劣的数量指标称为指标函数,最优指标函数记为fk(sk),它表示从第k段状态sk采用最优策略p*k,n到过程终止时的最佳效益值[1]。

最优指标函数其实就是我们真正关心的问题的解。

在上面的例子中,f2(B1)就表示从B1点到终点D1点的最短路径长度。

我们求解的最终目标就是f1(A1)。

最优指标函数的求法一般是一个从目标状态出发的递推公式,称为规划方程:

其中sk是第k段的某个状态,uk是从sk出发的允许决策集合Dk(sk)中的一个决策,Tk(sk,uk)是由sk和uk所导出的第k+1段的某个状态sk+1,g(x,uk)是定义在数值x和决策uk上的一个函数,而函数opt表示最优化,根据具体问题分别表为max或min。

,称为边界条件。

上例中的规划方程就是:

边界条件为

这里是一种从目标状态往回推的逆序求法,适用于目标状态确定的问题。

在我们的信息学问题中,也有很多有着确定的初始状态。

当然,对于初始状态确定的问题,我们也可以采用从初始状态出发往前推的顺序求法。

事实上,这种方法对我们来说要更为直观、更易设计一些,从而更多地出现在我们的解题过程中。

我们本节所讨论的这些理论虽然不是本文的主旨,但是却对下面要说的动态规划的特点起着基础性的作用。

§2动态规划的设计与实现

上面我们讨论了动态规划的一些理论,本节我们将通过几个例子中,动态规划的设计与实现,来了解动态规划的一些特点。

§2.1动态规划的多样性

[例2]花店橱窗布置问题(IOI99)试题见附录

本题虽然是本届IOI中较为简单的一题,但其中大有文章可作。

说它简单,是因为它有序,因此我们一眼便可看出这题应该用动态规划来解决。

但是,如何动态规划呢?

如何划分阶段,又如何选择状态呢?

<方法1>以花束的数目来划分阶段。

在这里,阶段变量k表示的就是要布置的花束数目(前k束花),状态变量sk表示第k束花所在的花瓶。

而对于每一个状态sk,决策就是第k-1束花应该放在哪个花瓶,用uk表示。

最优指标函数fk(sk)表示前k束花,其中第k束插在第sk个花瓶中,所能取得的最大美学值。

状态转移方程为

规划方程为

(其中A(i,j)是花束i插在花瓶j中的美学值)

边界条件

(V是花瓶总数,事实上这是一个虚拟的边界)

<方法2>以花瓶的数目来划分阶段。

在这里阶段变量k表示的是要占用的花瓶数目(前k个花瓶),状态变量sk表示前k个花瓶中放了多少花。

而对于任意一个状态sk,决策就是第sk束花是否放在第k个花瓶中,用变量uk=1或0来表示。

最优指标函数fk(sk)表示前k个花瓶中插了sk束花,所能取得的最大美学值。

状态转移方程为

规划方程为

边界条件为

两种划分阶段的方法,引出了两种状态表示法,两种规划方式,但是却都成功地解决了问题。

只不过因为决策的选择有多有少,所以算法的时间复杂度也就不同。

[2]

这个例子具有很大的普遍性。

有很多的多阶段决策问题都有着不止一种的阶段划分方法,因而往往就有不止一种的规划方法。

有时各种方法所产生的效果是差不多的,但更多的时候,就像我们的例子一样,两种方法会在某个方面有些区别。

所以,在用动态规划解题的时候,可以多想一想是否有其它的解法。

对于不同的解法,要注意比较,好的算法好在哪里,差一点的算法差在哪里。

从各种不同算法的比较中,我们可以更深刻地领会动态规划的构思技巧。

§2.2动态规划的模式性

这个可能做过动态规划的人都有体会,从我们上面对动态规划的分析也可以看出来。

动态规划的设计都有着一定的模式,一般要经历以下几个步骤。

划分阶段:

按照问题的时间或空间特征,把问题分为若干个阶段。

注意这若干个阶段一定要是有序的或者是可排序的,否则问题就无法求解。

选择状态:

将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。

当然,状态的选择要满足无后效性。

确定决策并写出状态转移方程:

之所以把这两步放在一起,是因为决策和状态转移有着天然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。

所以,如果我们确定了决策,状态转移方程也就写出来了。

但事实上,我们常常是反过来做,根据相邻两段的各状态之间的关系来确定决策。

写出规划方程(包括边界条件):

在第一部分中,我们已经给出了规划方程的通用形式化表达式。

一般说来,只要阶段、状态、决策和状态转移确定了,这一步还是比较简单的。

动态规划的主要难点在于理论上的设计,一旦设计完成,实现部分就会非常简单。

大体上的框架如下:

对f1(s1)初始化(边界条件)

fork2ton(这里以顺序求解为例)

对每一个skSk

fk(sk)一个极值(∞或-∞)

对每一个uk(sk)Dk(sk)

sk-1Tk(sk,uk)

tg(fk-1(sk-1),uk)

y

t比fk(sk)更优

n

fk(sk)t

输出fn(sn)

这个N-S图虽然不能代表全部,但足可以概括大多数。

少数的一些特殊的动态规划,其实现的原理也是类似,可以类比出来。

我们到现在对动态规划的分析,主要是在理论上、设计上,原因也就在此。

掌握了动态规划的模式性,我们在用动态规划解题时就可以把主要的精力放在理论上的设计。

一旦设计成熟,问题也就基本上解决了。

而且在设计算法时也可以按部就班地来。

但是“物极必反”,太过拘泥于模式就会限制我们的思维,扼杀优良算法思想的产生。

我们在解题时,不妨发挥一下创造性,去突破动态规划的实现模式,这样往往会收到意想不到的效果。

[3]

§2.3动态规划的技巧性

上面我们所说的动态规划的模式性,主要指的是实现方面。

而在设计方面,虽然它较为严格的步骤性,但是它的设计思想却是没有一定的规律可循的。

这就需要我们不断地在实践当中去掌握动态规划的技巧,下面仅就一个例子谈一点我自己的体会。

[例3]

街道问题:

在下图中找出从左下角到右上角的最短路径,每步只能向右方或上方走。

这是一道简单而又典型的动态规划题,许多介绍动态规划的书与文章中都拿它来做例子。

通常,书上的解答是这样的:

 

按照图中的虚线来划分阶段,即阶段变量k表示走过的步数,而状态变量sk表示当前处于这一阶段上的哪一点(各点所对应的阶段和状态已经用ks在地图上标明)。

这时的模型实际上已经转化成了一个特殊的多段图。

用决策变量uk=0表示向右走,uk=1表示向上走,则状态转移方程如下:

(这里的row是地图竖直方向的行数)

我们看到,这个状态转移方程需要根据k的取值分两种情况讨论,显得非常麻烦。

相应的,把它代入规划方程而付诸实现时,算法也很繁。

因而我们在实现时,一般是不会这么做的,而代之以下面方法:

将地图中的点规则地编号如上,得到的规划方程如下:

(这里Distance表示相邻两点间的边长)

这样做确实要比上面的方法简单多了,但是它已经破坏了动态规划的本来面目,而不存在明确的阶段特征了。

如果说这种方法是以地图中的行(A、B、C、D)来划分阶段的话,那么它的“状态转移”就不全是在两个阶段之间进行的了。

也许这没什么大不了的,因为实践比理论更有说服力。

但是,如果我们把题目扩展一下:

在地图中找出从左下角到右上角的两条路径,两条路径中的任何一条边都不能重叠,并且要求两条路径的总长度最短。

这时,再用这种“简单”的方法就不太好办了。

如果非得套用这种方法的话,则最优指标函数就需要有四维的下标,并且难以处理两条路径“不能重叠”的问题。

而我们回到原先“标准”的动态规划法,就会发现这个问题很好解决,只需要加一维状态变量就成了。

即用sk=(ak,bk)分别表示两条路径走到阶段k时所处的位置,相应的,决策变量也增加一维,用uk=(xk,yk)分别表示两条路径的行走方向。

状态转移时将两条路径分别考虑:

在写规划方程时,只要对两条路径走到同一个点的情况稍微处理一下,减少可选的决策个数:

从这个例子中可以总结出设计动态规划算法的一个技巧:

状态转移一般是在相邻的两个阶段之间(有时也可以在不相邻的两个阶段间),但是尽量不要在同一个阶段内进行。

动态规划是一种很灵活的解题方法,在动态规划算法的设计中,类似的技巧还有很多。

要掌握动态规划的技巧,有两条途径:

一是要深刻理解动态规划的本质,这也是我们为什么一开始就探讨它的本质的原因;二是要多实践,不但要多解题,还要学会从解题中探寻规律,

题目

有N件物品和一个容量为V的背包。

第i件物品的费用是c[i],价值是w[i]。

求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

基本思路

这是最基础的背包问题,特点是:

每种物品仅有一件,可以选择放或不放。

用子问题定义状态:

即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。

则其状态转移方程便是:

f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}。

这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。

所以有必要将它详细解释一下:

“将前i件物品放入容量为v的背包中”这个子问题,若只考虑第i件物品的策略(放或不放),那么就可以转化为一个只牵扯前i-1件物品的问题。

如果不放第i件物品,那么问题就转化为“前i-1件物品放入容量为v的背包中”;如果放第i件物品,那么问题就转化为“前i-1件物品放入剩下的容量为v-c[i]的背包中”,此时能获得的最大价值就是f[i-1][v-c[i]]再加上通过放入第i件物品获得的价值w[i]。

注意f[i][v]有意义当且仅当存在一个前i件物品的子集,其费用总和为v。

所以按照这个方程递推完毕后,最终的答案并不一定是f[N][V],而是f[N][0..V]的最大值。

如果将状态的定义中的“恰”字去掉,在转移方程中就要再加入一项f[i][v-1],这样就可以保证f[N][V]就是最后的答案。

至于为什么这样就可以,由你自己来体会了。

优化空间复杂度

以上方法的时间和空间复杂度均为O(N*V),其中时间复杂度基本已经不能再优化了,但空间复杂度却可以优化到O(V)。

先考虑上面讲的基本思路如何实现,肯定是有一个主循环i=1..N,每次算出来二维数组f[i][0..V]的所有值。

那么,如果只用一个数组f[0..V],能不能保证第i次循环结束后f[v]中表示的就是我们定义的状态f[i][v]呢?

f[i][v]是由f[i-1][v]和f[i-1][v-c[i]]两个子问题递推而来,能否保证在推f[i][v]时(也即在第i次主循环中推f[v]时)能够得到f[i-1][v]和f[i-1][v-c[i]]的值呢?

事实上,这要求在每次主循环中我们以v=V..0的顺序推f[v],这样才能保证推f[v]时f[v-c[i]]保存的是状态f[i-1][v-c[i]]的值。

伪代码如下:

fori=1..N

forv=V..0

f[v]=max{f[v],f[v-c[i]]+w[i]};

其中的f[v]=max{f[v],f[v-c[i]]}一句恰就相当于我们的转移方程f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]},因为现在的f[v-c[i]]就相当于原来的f[i-1][v-c[i]]。

如果将v的循环顺序从上面的逆序改成顺序的话,那么则成了f[i][v]由f[i][v-c[i]]推知,与本题意不符,但它却是另一个重要的背包问题P02最简捷的解决方案,故学习只用一维数组解01背包问题是十分必要的。

总结

01背包问题是最基本的背包问题,它包含了背包问题中设计状态、方程的最基本思想,另外,别的类型的背包问题往往也可以转换成01背包问题求解。

故一定要仔细体会上面基本思路的得出方法,状态转移方程的意义,以及最后怎样优化的空间复杂度。

P02:

完全背包问题

题目

有N种物品和一个容量为V的背包,每种物品都有无限件可用。

第i种物品的费用是c[i],价值是w[i]。

求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

基本思路

这个问题非常类似于01背包问题,所不同的是每种物品有无限件。

也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……等很多种。

如果仍然按照解01背包时的思路,令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值。

仍然可以按照每种物品不同的策略写出状态转移方程,像这样:

f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v}。

这跟01背包问题一样有O(N*V)个状态需要求解,但求解每个状态的时间则不是常数了,求解状态f[i][v]的时间是O(v/c[i]),总的复杂度是超过O(VN)的。

将01背包问题的基本思路加以改进,得到了这样一个清晰的方法。

这说明01背包问题的方程的确是很重要,可以推及其它类型的背包问题。

但我们还是试图改进这个复杂度。

一个简单有效的优化

完全背包问题有一个很简单有效的优化,是这样的:

若两件物品i、j满足c[i]<=c[j]且w[i]>=w[j],则将物品j去掉,不用考虑。

这个优化的正确性显然:

任何情况下都可将价值小费用高得j换成物美价廉的i,得到至少不会更差的方案。

对于随机生成的数据,这个方法往往会大大减少物品的件数,从而加快速度。

然而这个并不能改善最坏情况的复杂度,因为有可能特别设计的数据可以一件物品也去不掉。

转化为01背包问题求解

既然01背包问题是最基本的背包问题,那么我们可以考虑把完全背包问题转化为01背包问题来解。

最简单的想法是,考虑到第i种物品最多选V/c[i]件,于是可以把第i种物品转化为V/c[i]件费用及价值均不变的物品,然后求解这个01背包问题。

这样完全没有改进基本思路的时间复杂度,但这毕竟给了我们将完全背包问题转化为01背包问题的思路:

将一种物品拆成多件物品。

更高效的转化方法是:

把第i种物品拆成费用为c[i]*2^k、价值为w[i]*2^k的若干件物品,其中k满足c[i]*2^k

这是二进制的思想,因为不管最优策略选几件第i种物品,总可以表示成若干个2^k件物品的和。

这样把每种物品拆成O(log(V/c[i]))件物品,是一个很大的改进。

但我们有更优的O(VN)的算法。

*O(VN)的算法这个算法使用一维数组,先看伪代码:

fori=1..Nforv=0..Vf[v]=max{f[v],f[v-c[i]]+w[i]};

 

你会发现,这个伪代码与P01的伪代码只有v的循环次序不同而已。

为什么这样一改就可行呢?

首先想想为什么P01中要按照v=V..0的逆序来循环。

这是因为要保证第i次循环中的状态f[i][v]是由状态f[i-1][v-c[i]]递推而来。

换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第i件物品”这件策略时,依据的是一个绝无已经选入第i件物品的子结果f[i-1][v-c[i]]。

而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第i种物品”这种策略时,却正需要一个可能已选入第i种物品的子结果f[i][v-c[i]],所以就可以并且必须采用v=0..V的顺序循环。

这就是这个简单的程序为何成立的道理。

这个算法也可以以另外的思路得出。

例如,基本思路中的状态转移方程可以等价地变形成这种形式:

f[i][v]=max{f[i-1][v],f[i][v-c[i]]+w[i]},将这个方程用一维数组实现,便得到了上面的伪代码。

总结

完全背包问题也是一个相当基础的背包问题,它有两个状态转移方程,分别在“基本思路”以及“O(VN)的算法“的小节中给出。

希望你能够对这两个状态转移方程都仔细地体会,不仅记住,也要弄明白它们是怎么得出来的,最好能够自己想一种得到这些方程的方法。

事实上,对每一道动态规划题目都思考其方程的意义以及如何得来,是加深对动态规划的理解、提高动态规划功力的好方法。

P03:

多重背包问题

题目

有N种物品和一个容量为V的背包。

第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。

求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

基本算法

这题目和完全背包问题很类似。

基本的方程只需将完全背包问题的方程略微一改即可,因为对于第i种物品有n[i]+1种策略:

取0件,取1件……取n[i]件。

令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值,则:

f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]}。

复杂度是O(V*∑n[i])。

转化为01背包问题

另一种好想好写的基本方法是转化为01背包求解:

把第i种物品换成n[i]件01背包中的物品,则得到了物品数为∑n[i]的01背包问题,直接求解,复杂度仍然是O(V*∑n[i])。

但是我们期望将它转化为01背包问题之后能够像完全背包一样降低复杂度。

仍然考虑二进制的思想,我们考虑把第i种物品换成若干件物品,使得原问题中第i种物品可取的每种策略——取0..n[i]件——均能等价于取若干件代换以后的物品。

另外,取超过n[i]件的策略必不能出现。

方法是:

将第i种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。

使这些系数分别为1,2,4,...,2^(k-1),n[i]-2^k+1,且k是满足n[i]-2^k+1>0的最大整数。

例如,如果n[i]为13,就将这种物品分成系数分别为1,2,4,6的四件物品。

分成的这几件物品的系数和为n[i],表明不可能取多于n[i]件的第i种物品。

另外这种方法也能保证对于0..n[i]间的每一个整数,均可以用若干个系数的和表示,这个证明可以分0..2^k-1和2^k..n[i]两段来分别讨论得出,并不难,希望你自己思考尝试一下。

这样就将第i种物品分成了O(logn[i])种物品,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 农林牧渔 > 林学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1