第8课 分治.docx
- 文档编号:9649959
- 上传时间:2023-02-05
- 格式:DOCX
- 页数:10
- 大小:18.78KB
第8课 分治.docx
《第8课 分治.docx》由会员分享,可在线阅读,更多相关《第8课 分治.docx(10页珍藏版)》请在冰豆网上搜索。
第8课分治
分治法
1、分治法的基本思想
任何一个可以用计算机求解的问题所需的计算时间都与其规模N有关。
问题的规模越小,越容易直接求解,解题所需的计算时间也越少。
例如,对于n个元素的排序问题,当n=1时,不需任何计算;n=2时,只要作一次比较即可排好序;n=3时只要作3次比较即可,…。
而当n较大时,问题就不那么容易处理了。
要想直接解决一个规模较大的问题,有时是相当困难的。
分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。
如果原问题可分割成k个子问题(1 由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。 在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。 这自然导致递归过程的产生。 分治与递归就像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法。 2、分治法的适用条件 分治法所能解决的问题一般具有以下几个特征: (1)该问题的规模缩小到一定的程度就可以容易地解决; (2)该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质; (3)利用该问题分解出的子问题的解可以合并为该问题的解; (4)该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。 上述的第一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加;第二条特征是应用分治法的前提,它也是大多数问题可以满足的,此特征反映了递归思想的应用;第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑贪心法或动态规划法。 第四条特征涉及到分治法的效率,如果各子问题是不独立的,则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好。 3、分治法的基本步骤 分治法在每一层递归上都有三个步骤: (1)分解: 将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题; (2)解决: 若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题; (3)合并: 将各个子问题的解合并为原问题的解。 快速排序是基于分治策略的一个排序算法: 例题1: 输入20个数,将它们按照从高到低的次序排列以后输出。 快速排序是对冒泡排序的一种改进。 它的基本思想是: 通过一趟排序将要排序的数据分割成独立的左右两部分,其中一部分的所有数据都比另外一部分的所有数据要小,而另一部分的所有数据都比前一部分的所有数据要大,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,直到每一个待处理的序列的长度为1,处理结束。 具体操作: 假设要排序的数组是A[1]……A[N],首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。 比如: A[1]A[2]A[3]A[4]A[5]A[6]A[7] 49386527761397 一趟快速排序之后97766549132738 一趟快速排序的算法是: 1)设置两个变量I、J,排序开始的时候I: =1,J: =N; 2)以第一个数组元素作为关键数据,赋值给X,即X: =A[1]; 3)从J开始向前搜索,即由后开始向前搜索(J: =J-1),找到第一个大于X的值,两者交换; 4)从I开始向后搜索,即由前开始向后搜索(I: =I+1),找到第一个小于X的值,两者交换; 5)、重复第3、4步,直到I=J; 例如: 待排序的数组A的值分别是: (初始关键数据X: =49) A[1]A[2]A[3]A[4]A[5]A[6]A[7] 49386527761397从后搜,交换前I=1;J=7;交换后I=2;J=7 97386527761349从前搜,交换前I=2;J=7;交换后I=2;J=6 97496527761338从后搜,交换前I=2;J=6;交换后I=3;J=5 97766513492738从前搜,交换前I=3;J=5;交换后I=4;J=5 97766549132738从后搜,当I=4;J=4结束 经过一趟快速排序之后的结果是: 97766549132738,即所有大于49的数全部在49的前面,所有小于49的数全部在49的后面。 一趟快速排序的程序段: x: =a[i]; repeat while(a[j] j: =j-1; ifj>ithen{找到比x大的数后和前面的数进行交换} begin w: =a[i]; a[i]: =a[j]; a[j]: =w; i: =i+1;{交换之后i的值应该增加,定位到后一个} end; while(a[i]>x)and(i i: =i+1; ifi begin w: =a[j]; a[j]: =a[i]; a[i]: =w; j: =j-1;{交换之后j的值应该减少,定位到前一个} end untili=j; 整个快速排序过程的实现: 利用分治思想(即大化小的策略)可进一步对分开的两组数据再次分别进行快速排序,照此继续,直到分组对象只有一个数据为止。 我们可以将一趟快速排序写成过程,快速排序就是递归调用此过程。 在上面的例子中,以49为中点分割这个数据序列,然后分别对前面一部分和后面一部分进行类似的快速排序,从而完成全部数据序列的快速排序,最后把此数据序列变成一个有序的序列,根据这种思想对于上述数组A的快速排序的全过程如图所示: 初始状态{49386597761327} 进行一次快速排序之后划分为{977665}49{132738} 分别对前后两部分进行快速排序97{7665}49{3827}13 结束{76}{65}{38}{27}结束 结束结束结束结束 完整的过程: procedurequicksort(vara: array;s,e: integer); vari,j,x,w: integer; begin i: =s; j: =e; x: =a[i]; repeat while(a[j] j: =j-1; ifj>ithen{找到比x大的数后和前面的数进行交换} begin w: =a[i]; a[i]: =a[j]; a[j]: =w; i: =i+1;{交换之后i的值应该增加,定位到后一个} end; while(a[i]>x)and(i i: =i+1; ifi begin w: =a[j]; a[j]: =a[i]; a[i]: =w; j: =j-1;{交换之后j的值应该减少,定位到前一个} end untili=j; i: =i+1; j: =j-1; ifs ifi end; 完整的参考程序如下: programkuaisu(input,output); const n=20; var s: array[1..n]ofreal; m: integer; procedurequicksort(vara: array;s,e: integer); var i,j,x,w: integer; begin i: =s; j: =e; x: =a[i]; repeat while(a[j] j: =j-1; ifj>ithen{找到比x大的数后和前面的数进行交换} begin w: =a[i]; a[i]: =a[j]; a[j]: =w; i: =i+1;{交换之后i的值应该增加,定位到后一个} end; while(a[i]>x)and(i i: =i+1; ifi begin w: =a[j]; a[j]: =a[i]; a[i]: =w; j: =j-1;{交换之后j的值应该减少,定位到前一个} end untili=j; i: =i+1; j: =j-1; ifs ifi end;{过程结束} Begin Writeln('input20integernum: '); Form: =1tondo read(s[m]); m: =1; quicksort(s,m,n); Form: =1tondo write(s[m]: 4: 0) End. 例3: 归并排序 归并就是将多个有序的数列合成一个有序的数列。 将两个有序序列合并为一个有序序列叫二路归并(merge).归并排序就是n长度为1的子序列,两两归并最后变为有序的序列。 程序代码如下: programgbpx; constmaxn=7; typearr=array[1..maxn]ofinteger; vara,b,c: arr; i: integer; proceduremerge(r: arr;l,m,n: integer;varr2: arr); vari,j,k,p: integer; begin i: =l;j: =m+1;k: =l-1; while(i<=m)and(j<=n)do begin k: =k+1; ifr[i]<=r[j]thenbeginr2[k]: =r[i];i: =i+1end elsebeginr2[k]: =r[j];j: =j+1end end; ifi<=mthen forp: =itomdobegink: =k+1;r2[k]: =r[p]end; ifj<=nthen forp: =jtondobegink: =k+1;r2[k]: =r[p]end; end; proceduremergesort(varr,r1: arr;s,t: integer); vark: integer;c: arr; begin ifs=tthenr1[s]: =r[s]else begin k: =(s+t)div2; mergesort(r,c,s,k); mergesort(r,c,k+1,t); merge(c,s,k,t,r1) end; end; begin write('Enterdata: '); fori: =1tomaxndo read(a[i]); mergesort(a,b,1,maxn); fori: =1tomaxndo write(b[i]: 9); writeln; end. 练习: 1。 写出二分查找的程序。 2。 赛程问题。 有n(n=2^m)编号为1到n的运动队,参加某项运动的单循环比赛,请安排一个比赛日程? (共n-1天比赛,每天每队必须比赛一场)。 思考题1: 最接近点对问题 在应用中,常用诸如点、圆等简单的几何对象代表现实世界中的实体。 在涉及这些几何对象的问题中,常需要了解其邻域中其他几何对象的信息。 例如,在空中交通控制问题中,若将飞机作为空间中移动的一个点来看待,则具有最大碰撞危险的2架飞机,就是这个空间中最接近的一对点。 这类问题是计算几何学中研究的基本问题之一。 下面我们着重考虑平面上的最接近点对问题。 最接近点对问题的提法是: 给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。 严格地说,最接近点对可能多于1对。 为了简单起见,这里只限于找其中的一对。 思考题2: 导线和开关问题 如图1所示,具有3根导线的电缆把A区和B区连接起来。 在A区3根导线标以1,2,3;在B区导线1和3被连到开关3,导线2连到开关1。 图1一个有3条导线和3个开关的实例 一般说来,电缆含m(1<=m<=90)根导线,在A区标以1,2,...,m。 在B区有m个开关,标为1,2,..,m。 每一根导线都被严格地连到这些开关中的某一个上;每一个开关上可以连有0根或多根导线。 怎样快速测试哪根导线连在哪个开关上?
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第8课 分治