`
hdy007
  • 浏览: 29715 次
最近访客 更多访客>>
文章分类
社区版块
存档分类

常用算法设计方法之分治法

阅读更多

<o:p> </o:p>

1、分治法的基本思想<o:p></o:p>

任何一个可以用计算机求解的问题所需的计算时间都与其规模N有关。问题的规模越小,越容易直接求解,解题所需的计算时间也越少。例如,对于n个元素的排序问题,当n=1时,不需任何计算;n=2时,只要作一次比较即可排好序;n=3时只要作3次比较即可,。而当n较大时,问题就不那么容易处理了。要想直接解决一个规模较大的问题,有时是相当困难的。<o:p></o:p>

分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。<o:p></o:p>

如果原问题可分割成k个子问题(1<k≤n),且这些子问题都可解,并可利用这些子问题的解求出原问题的解,那么这种分治法就是可行的。由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。这自然导致递归过程的产生。分治与递归像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法。<o:p></o:p>

2、分治法的适用条件<o:p></o:p>

分治法所能解决的问题一般具有以下几个特征:<o:p></o:p>

1)该问题的规模缩小到一定的程度就可以容易地解决;<o:p></o:p>

2)该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质;<o:p></o:p>

3)利用该问题分解出的子问题的解可以合并为该问题的解;<o:p></o:p>

4)该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。<o:p></o:p>

上述的第一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加;第二条特征是应用分治法的前提,它也是大多数问题可以满足的,此特征反映了递归思想的应用;第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑贪心法或动态规划法。第四条特征涉及到分治法的效率,如果各子问题是不独立的,则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好。<o:p></o:p>

3、分治法的基本步骤<o:p></o:p>

分治法在每一层递归上都有三个步骤:<o:p></o:p>

1)分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;<o:p></o:p>

2)解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题;<o:p></o:p>

3)合并:将各个子问题的解合并为原问题的解。<o:p></o:p>

它的一般的算法设计模式如下:<o:p></o:p>

Divide_and_ConquerP<o:p></o:p>

if |P|≤n0<o:p></o:p>

then returnADHOCP))<o:p></o:p>

P分解为较小的子问题P1P2Pk<o:p></o:p>

for i←1 to k<o:p></o:p>

do<o:p></o:p>

yi ← Divide-and-ConquerPi       递归解决Pi<o:p></o:p>

T ← MERGEy1y2yk         合并子问题<o:p></o:p>

ReturnT<o:p></o:p>

其中 |P| 表示问题P的规模;n0为一阈值,表示当问题P的规模不超过n0时,问题已容易直接解出,不必再继续分解。ADHOCP)是该分治法中的基本子算法,用于直接解小规模的问题P。因此,当P的规模不超过n0时,直接用算法ADHOCP)求解。<o:p></o:p>

算法MERGEy1y2yk)是该分治法中的合并子算法,用于将P的子问题P1P2Pk的相应的解y1y2yk合并为P的解。<o:p></o:p>

根据分治法的分割原则,原问题应该分为多少个子问题才较适宜?各个子问题的规模应该怎样才为适当?这些问题很难予以肯定的回答。但人们从大量实践中发现,在用分治法设计算法时,最好使子问题的规模大致相同。换句话说,将一个问题分成大小相等的k个子问题的处理方法是行之有效的。许多问题可以取k=2。这种使子问题规模大致相等的做法是出自一种平衡子问题的思想,它几乎总是比子问题规模不等的做法要好。<o:p></o:p>

分治法的合并步骤是算法的关键所在。有些问题的合并方法比较明显,有些问题合并方法比较复杂,或者是有多种合并方案;或者是合并方案不明显。究竟应该怎样合并,没有统一的模式,需要具体问题具体分析。<o:p></o:p>

【问题】   大整数乘法<o:p></o:p>

问题描述:<o:p></o:p>

通常,在分析一个算法的计算复杂性时,都将加法和乘法运算当作是基本运算来处理,即将执行一次加法或乘法运算所需的计算时间当作一个仅取决于计算机硬件处理速度的常数。<o:p></o:p>

这个假定仅在计算机硬件能对参加运算的整数直接表示和处理时才是合理的。然而,在某些情况下,我们要处理很大的整数,它无法在计算机硬件能直接表示的范围内进行处理。若用浮点数来表示它,则只能近似地表示它的大小,计算结果中的有效数字也受到限制。若要精确地表示大整数并在计算结果中要求精确地得到所有位数上的数字,就必须用软件的方法来实现大整数的算术运算。<o:p></o:p>

请设计一个有效的算法,可以进行两个n位大整数的乘法运算。<o:p></o:p>

XY都是n位的二进制整数,现在要计算它们的乘积XY。我们可以用小学所学的方法来设计一个计算乘积XY的算法,但是这样做计算步骤太多,显得效率较低。如果将每21位数的乘法或加法看作一步运算,那么这种方法要作O(n2)步运算才能求出乘积XY。下面我们用分治法来设计一个更有效的大整数乘积算法。<o:p></o:p>

<o:p> </o:p>

6-3 大整数XY的分段<o:p></o:p>

我们将n位的二进制整数XY各分为2段,每段的长为n/2位(为简单起见,假设n2的幂),如图6-3所示。<o:p></o:p>

由此,X=A2n/2+BY=C2n/2+D。这样,XY的乘积为:<o:p></o:p>

XY=(A2n/2+B)(C2n/2+D)=AC2n+(AD+CB)2n/2+BD   1<o:p></o:p>

如果按式(1)计算XY,则我们必须进行4n/2位整数的乘法(ACADBCBD),以及3次不超过n位的整数加法(分别对应于式(1)中的加号),此外还要做2次移位(分别对应于式(1)中乘2n和乘2n/2)。所有这些加法和移位共用On)步运算。设Tn)是2n位整数相乘所需的运算总数,则由式(1),我们有:<o:p></o:p>

2<o:p></o:p>

由此可得Tn=On2)。因此,用(1)式来计算XY的乘积并不比小学生的方法更有效。要想改进算法的计算复杂性,必须减少乘法次数。为此我们把XY写成另一种形式:<o:p></o:p>

XY=AC2n+[(A-B)(D-C)+AC+BD]2n/2+BD       3<o:p></o:p>

虽然,式(3)看起来比式(1)复杂些,但它仅需做3n/2位整数的乘法(ACBD和(A-B)(D-C)),6次加、减法和2次移位。由此可得:<o:p></o:p>

4<o:p></o:p>

用解递归方程的套用公式法马上可得其解为T(n)=O(nlog3)=O(n1.59)。利用式(3),并考虑到XY的符号对结果的影响,我们给出大整数相乘的完整算法MULT如下:<o:p></o:p>

function MULT(XYn); {XY2个小于2n的整数,返回结果为XY的乘积XY}<o:p></o:p>

begin<o:p></o:p>

S=SIGN(X)*SIGN(Y); {SXY的符号乘积}<o:p></o:p>

X=ABS(X);<o:p></o:p>

Y=ABS(Y); {XY分别取绝对值}<o:p></o:p>

if n=1 then<o:p></o:p>

if (X=1)and(Y=1) then return(S)<o:p></o:p>

else return(0)<o:p></o:p>

else begin<o:p></o:p>

A=X的左边n/2;<o:p></o:p>

B=X的右边n/2;<o:p></o:p>

C=Y的左边n/2;<o:p></o:p>

D=Y的右边n/2;<o:p></o:p>

ml=MULT(A,C,n/2);<o:p></o:p>

m2=MULT(A-B,D-C,n/2);<o:p></o:p>

m3=MULT(B,D,n/2);<o:p></o:p>

S=S*(m1*2n+(m1+m2+m3)*2n/2+m3);<o:p></o:p>

return(S);<o:p></o:p>

end;<o:p></o:p>

end;<o:p></o:p>

上述二进制大整数乘法同样可应用于十进制大整数的乘法以提高乘法的效率减少乘法次数。<o:p></o:p>

【问题】   最接近点对问题<o:p></o:p>

问题描述:<o:p></o:p>

在应用中,常用诸如点、圆等简单的几何对象代表现实世界中的实体。在涉及这些几何对象的问题中,常需要了解其邻域中其他几何对象的信息。例如,在空中交通控制问题中,若将飞机作为空间中移动的一个点来看待,则具有最大碰撞危险的2架飞机,就是这个空间中最接近的一对点。这类问题是计算几何学中研究的基本问题之一。下面我们着重考虑平面上的最接近点对问题。<o:p></o:p>

最接近点对问题的提法是:给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。<o:p></o:p>

严格地说,最接近点对可能多于1对。为了简单起见,这里只限于找其中的一对。<o:p></o:p>

这个问题很容易理解,似乎也不难解决。我们只要将每一点与其他n-1个点的距离算出,找出达到最小距离的两个点即可。然而,这样做效率太低,需要O(n2)的计算时间。我们能否找到问题的一个O (nlogn)算法。<o:p></o:p>

这个问题显然满足分治法的第一个和第二个适用条件,我们考虑将所给的平面上n个点的集合S分成2个子集S1S2,每个子集中约有n/2个点,然后在每个子集中递归地求其最接近的点对。在这里,一个关键的问题是如何实现分治法中的合并步骤,即由S1S2的最接近点对,如何求得原集合S中的最接近点对,因为S1S2的最接近点对未必就是S的最接近点对。如果组成S的最接近点对的2个点都在S1中或都在S2中,则问题很容易解决。但是,如果这2个点分别在S1S2中,则对于S1中任一点pS2中最多只有n/2个点与它构成最接近点对的候选者,仍需做n2/4次计算和比较才能确定S的最接近点对。因此,依此思路,合并步骤耗时为O(n2)。整个算法所需计算时间T(n)应满足:<o:p></o:p>

T(n)=2T(n/2)+O(n2)<o:p></o:p>

它的解为T(n)=O(n2),即与合并步骤的耗时同阶,显示不出比用穷举的方法好。从解递归方程的套用公式法,我们看到问题出在合并步骤耗时太多。这启发我们把注意力放在合并步骤上。<o:p></o:p>

为了使问题易于理解和分析,我们先来考虑一维的情形。此时S中的n个点退化为x轴上的n个实数x1x2xn。最接近点对即为这n个实数中相差最小的2个实数。我们显然可以先将x1x2xn排好序,然后,用一次线性扫描就可以找出最接近点对。这种方法主要计算时间花在排序上,因此如在排序算法中所证明的,耗时为O(nlogn)。然而这种方法无法直接推广到二维的情形。因此,对这种一维的简单情形,我们还是尝试用分治法来求解,并希望能推广到二维的情形。<o:p></o:p>

假设我们用x轴上某个点mS划分为2个子集S1S2,使得S1={x∈S | x≤m}S2={x∈S | x>m}。这样一来,对于所有p∈S1q∈S2p<q<o:p></o:p>

递归地在S1S2上找出其最接近点对{p1p2}{q1q2},并设δ=min{|p1-p2||q1-q2|}S中的最接近点对或者是{p1p2},或者是{q1q2},或者是某个{p3q3},其中p3∈S1q3∈S2。如图1所示。<o:p></o:p>

<o:p> </o:p>

1 一维情形的分治法<o:p></o:p>

我们注意到,如果S的最接近点对是{p3q3},即 | p3-q3 | < δ,则p3q3两者与m的距离不超过δ,即 | p3-m | < δ| q3-m | < δ,也就是说,p3∈(m-δm)q3∈(mm+δ)。由于在S1中,每个长度为δ的半闭区间至多包含一个点(否则必有两点距离小于δ),并且mS1S2的分割点,因此(m-δm)中至多包含S中的一个点。同理,(mm+δ)中也至多包含S中的一个点。由图1可以看出,如果(m-δm)中有S中的点,则此点就是S1中最大点。同理,如果(mm+δ)中有S中的点,则此点就是S2中最小点。因此,我们用线性时间就能找到区间(m-δm)(mm+δ)中所有点,即p3q3。从而我们用线性时间就可以将S1的解和S2的解合并成为S的解。也就是说,按这种分治策略,合并步可在O(n)时间内完成。这样是否就可以得到一个有效的算法了呢?<o:p></o:p>

还有一个问题需要认真考虑,即分割点m的选取,及S1S2的划分。选取分割点m的一个基本要求是由此导出集合S的一个线性分割,即S=S1∪S2 S1∩S2=Φ,且S1 {x | x≤m}S2 {x | x>m}。容易看出,如果选取m=[maxS+minS]/2,可以满足线性分割的要求。选取分割点后,再用O(n)时间即可将S划分成S1={x∈S | x≤m}S2={x∈S | x>m}。然而,这样选取分割点m,有可能造成划分出的子集S1S2的不平衡。例如在最坏情况下,|S1|=1|S2|=n-1,由此产生的分治法在最坏情况下所需的计算时间Tn)应满足递归方程:<o:p></o:p>

Tn=Tn-1+On<o:p></o:p>

它的解是Tn=On2)。这种效率降低的现象可以通过分治法中平衡子问题的方法加以解决。也就是说,我们可以通过适当选择分割点m,使S1S2中有大致相等个数的点。自然地,我们会想到用Sn个点的坐标的中位数来作分割点。在选择算法中介绍的选取中位数的线性时间算法使我们可以在On)时间内确定一个平衡的分割点m<o:p></o:p>

至此,我们可以设计出一个求一维点集S中最接近点对的距离的算法pair如下。<o:p></o:p>

Float pairS;<o:p></o:p>

{   if | S | =2   δ= | x[2]x[1] |     /*x[1..n]存放的是Sn个点的坐标*/<o:p></o:p>

else<o:p></o:p>

{   if ( | S | =1)   δ=∞<o:p></o:p>

else<o:p></o:p>

{   m=S中各点的坐标值的中位数;<o:p></o:p>

构造S1S2,使S1={x∈S | x≤m}S2={x∈S | xm};<o:p></o:p>

δ1=pair(S1);<o:p></o:p>

δ2=pair(S2);<o:p></o:p>

p=max(S1);<o:p></o:p>

q=min(S2);<o:p></o:p>

δ=min(δ1δ2q-p);<o:p></o:p>

}<o:p></o:p>

return(δ);<o:p></o:p>

}<o:p></o:p>

由以上的分析可知,该算法的分割步

分享到:
评论

相关推荐

    常用算法分析设计(分治、动态规划、分支限界、回溯、贪婪等等)

    详细介绍了常用的算法设计法,包括:分治、递归、动态规划、分支限界、回溯、贪婪、排列组合、图论算法等等

    常用算法设计方法常用算法设计方法

    算法设计是一件非常困难的工作,经常采用的算法设计技术主要有迭代法、穷举搜索法、递推法、贪婪法、回溯法、分治法、动态规划法等等。另外,为了更简洁的形式设计和描述算法,在算法设计时又常常采用递归技术,用...

    算法分析与设计 第三讲 分治法

    常用的算法设计技术有迭代法、穷举搜索法、递推法、贪婪法、回溯法、分治法和动态规划法等。另外,为了以更简洁的形式设计和描述算法,在设计算法时常采用递归技术,用递归描述算法。 本讲中,主要介绍分治法。

    常用算法设计方法(C语言)

    C语言的一些常用算法设计方法,包括迭代法、穷举搜索法、递推法、贪婪法、回溯法、分治法、动态规划法等等

    常用算法设计方法.doc

    算法设计是一件非常困难的工作,经常采用的算法设计技术主要有迭代法、穷举搜索法、递推法、贪婪法、回溯法、分治法、动态规划法等等。另外,为了更简洁的形式设计和藐视算法,在算法设计时又常常采用递归技术,用...

    常用算法设计方法(编程入门者使用,C语言例题)

    编程常用算法,菜鸟级 (迭代法,穷举搜索法,递推法,递归,回溯法,分治法等)

    算法设计与分析(详细解析(含源代码))

    常用算法设计方法详细解析(含源代码) 算法是问题求解过程的精确描述,一个算法由有限条可完全机械地执行的、有确定结果的指令组成。指令正确地描述了要完成的任务和它们被执行的顺序。计算机按算法指令所描述的...

    常用算法设计方法(C语言).

    算法设计的各种方法都有,如迭代法、穷举搜索法、递推法、贪婪法、回溯法、分治法、动态规划法,且有例子

    常用算法设计方法+搜集

    算法设计是一件非常困难的工作,经常采用的算法设计技术主要有迭代法、穷举搜索法、递推法、贪婪法、回溯法、分治法、动态规划法等等。

    C 常用算法设计方法.docx

    算法设计是一件非常困难的工作,经常采用的算法设计技术主要有迭代法、穷举搜索法、递推法、贪婪法、回溯法、分治法、动态规划法等等

    Matlab常用算法大集合.zip

    Matlab常用算法大集合: Floyd算法.rar 免疫算法.rar 分治算法.rar 动态规划.rar 图论.rar 学习路线.png 搜索算法.rar 概率算法.rar 模拟退火算法.rar 灰色预测.rar 穷举法求解0-1整数规划的matlab程序.rar 类比法....

    算法设计与分析-1排序算法性能分析-冒泡/选择/插入/合并/快速排序-pre ppt

    合并排序算法和快速排序算法采用了采用分治法、递归的方法,将时间复杂度降为O(nlogn)。在本次实验中将数据量提到5万的时候,该类算法运行时间仍在几毫秒左右,而上面的3种算法运行时间已经到达十几秒左右,效率...

    算法设计与分析课件

    第2章介绍常用数学工具,第3章从算法的观点介绍了NP完全理论,从第4章~第12章分别介绍了蛮力法、分治法、减治法、动态规划法、贪心法、回溯法、分支限界法、概率算法和近似算法等算法设计技术。课程中所配算法均给出...

    算法设计与分析教学大纲

    在能力方面要求:通过本课程的学习,学生要掌握几种常用的算法设计策略,包括递归与分治策略、动态规划算法、贪心算法、回溯法、分支限界法概率算法、线性规划和网络流法和NP完全性理论与近似算法等,并会分析算法的...

    计算机算法设计与分析

    它以算法设计策略为知识单元系统地介绍计算机算法的设计方法和分析技巧。其主要内容包括:算法及算法复杂性基本概念,算法描述,有效算法最常用的设计策略--递归和分治法,动态规划法的设计要点与适用性,贪心算法,...

    java算法程序技巧源代码

    用java写的算法程序源代码,包括常用技巧,分治法,递归,动态规划算法。完整,高效。

    C语言版常用算法设计技术

    经常采用的算法设计技术主要有迭代法、穷举搜索法、递推法、贪婪法、回溯法、分治法、动态规划法等等。另外,为了更简洁的形式设计和藐视算法,在算法设计时又常常采用递归技术,用递归描述算法等。

    C++数据结构知识点与经典算法整理

    1.常用的算法设计方法: 102 1.1 迭代法: 102 1.2 穷举搜索法: 103 1.3 递推法: 104 1.4 递归法 106 1.5 贪婪法 111 1.6 分治法 113 1.7 动态规划法 115 1.8 回溯法 119 1.9 分支定界法: 120 2.几个重要的算法...

    算法导论(part1)

    因为书中讨论了算法设计中的工程问题及其数学性质,因此,本书也可以供专业技术人员自学之用。 本书是第2版。在这个版本里,我们对全书进行了更新。所做的改动从新增了若干章,到个别语句的改写。 致使用本书的...

Global site tag (gtag.js) - Google Analytics