290 likes | 475 Views
每节一经典 对大问题“ 分而治之,各个击破 ” :. 计算机科学学院 王小明 ( 博士 / 教授 / 博士生导师 ) Email: wangxm@snnu.edu.cn. 分治法 : 把一个难于直接解决的大问题分解为若干个“相似”的小问题,再解所有小问题,然后把小问题的解“合并”,从而得到大问题的解 。 即:分治法是递归设计方法的一种具体策略 。 例如 :折半查找,快速排序,二叉树遍历,等等。. 第 4 讲 分治法. 分治法适用的条件 分治法所能解决的问题一般具有以下几个特征 : 该问题的规模缩小到一定的程度就可以容易地解决;
E N D
每节一经典 对大问题“分而治之,各个击破 ”: 计算机科学学院 王小明 (博士/教授/博士生导师) Email: wangxm@snnu.edu.cn
分治法:把一个难于直接解决的大问题分解为若干个“相似”的小问题,再解所有小问题,然后把小问题的解“合并”,从而得到大问题的解。分治法:把一个难于直接解决的大问题分解为若干个“相似”的小问题,再解所有小问题,然后把小问题的解“合并”,从而得到大问题的解。 即:分治法是递归设计方法的一种具体策略。 例如:折半查找,快速排序,二叉树遍历,等等。 第4讲 分治法
分治法适用的条件 分治法所能解决的问题一般具有以下几个特征: 该问题的规模缩小到一定的程度就可以容易地解决; 该问题可以分解为若干个规模较小的相似问题; 利用该问题分解出的子问题的解可以合并为该问题的解; 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。 第4讲 分治法
第4讲 分治法 注意:如果各子问题是不独立的,则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然也可用分治法,但一般用动态规划较好。 适合用分治法 不适合用分治法
分治法设计框架 1)分解:把原问题分解为多个规模较小、相 互独立、形式相同的子问题; 2)解决:解决各个子问题(可能还需要分解); 3)合并:将已得到的所有子问题的解合并为原问题 的解。 注意:有些问题分解后,不必求所有子问题的解。 例如:折半查找。在下列序列中找数字2: 1,2,3,4,5,6,7 第4讲 分治法
分治法算法框架 divide-and-conquer(P) {if ( n<= n0) then{解子问题; return(子问题的解)} for (i=1,i<=k,i++) {分解原问题为更小的子问题 Pi yi=divide-and-conquer(Pi); //递归的解各子问题 } T= merge(y1,...,yk) ;//将子问题的解yi合并为原问题的解 return(T) } 第4讲 分治法
问题分解应注意的事项: 人们从大量实践中发现,在用分治法设计算法时,最好使子问题的规模大致相同。即将一个问题分成大小相等的k个子问题的处理方法是行之有效的。这种使子问题规模大致相等的做法是出自一种平衡(balancing)子问题的思想,它几乎总是比子问题规模不等的做法要好。 第4讲 分治法
分治法举例 例13. 金块问题。 老板有n个金块,希望最优秀的雇员得到其中最重的一块,最差的雇员得到其中最轻的一块。假设有一台比较重量的仪器,如何用最少的比较次数找出最重和最轻的金块? 第4讲 分治法
理解金块问题:以9以内的实例理解问题。 第4讲 分治法 问题:1.最重的是那块?用max标记 2.最轻的是那块?用min标记
算法策略:用蛮力法。即从第一块开始,查找哪块最重,哪块最轻。算法策略:用蛮力法。即从第一块开始,查找哪块最重,哪块最轻。 第4讲 分治法 a[1] a[2] a[3] a[4] a[5] 1) max min 2) <? <? … min
算法设计: Maxmin(float a[],int n) {max=a[1];min=a[1]; for(i=2;i<=n;i=i+1) {if(max<a[i]) max=a[i] else if(min>a[i]) min=a[i] } Return(max, min) } 第4讲 分治法
第4讲 分治法 算法分析:(1)时间复杂性和空间复杂性。 分析该算法可以看出,比较操作 max<a[i]和mix<a[i]是执行频次最高的关键语句。因此以这两个语句执行的总次数作为该算法执行所需要的时间。最好情况下,金块由轻到重排列,不需要进行min<a[i]比较,而 max<a[i]比较共需进行n-1次,即可得到max和min; 最坏情况下,金块由重到轻排列,还需要进行n-1次min<a[i]比较,才能得到最终的min,因此共进行2(n-1)次比较。在平均情况下(概率平均),a[i]将有一半的时间比max大,因此平均比较次数是3(n-1)/2。所以算法时间复杂度为O(n). 算法共用了n个存贮空间(a[i]占用的空间),所以空间复杂度为S(n).
第4讲 分治法 算法正确性分析: 算法的正确性分析包含两方面的含义:1)算法是可终止的。2)算法是有效的。 在上述算法中,由于n是有限数,所以算法在有限次执行之后必然终止,这是显然的。 算法的有效性是指当算法正常终止时,最重、最轻的金块能够被找到(没有遗漏现象)。由于算法是从第一个金块开始逐一寻找,直到和第n个金块比较之后才结束,所以最后得到的必然是最重(max)、最轻(min)的金块.综合1)和2),算法是正确的。
第4讲 分治法 用分治法解决金块问题 典型二分法思想:一种简单的分治法。即当每次将比较大的一个问题一分为二,形成两个较小的问题,再把每个较小问题一分为二,变为更小的两个问题,……,直到得到容易解决的小问题为止,再解决所有小问题,然后把小问题的解逐层合并,得到原来大问题的解。
第4讲 分治法 典型二分法示意图: 原问题 子问题2 子问题1 子问题3 子问题4 子问题5 子问题6 ……
第4讲 分治法 典型二分法用二叉树表示: ……
第4讲 分治法 • 用二分法如何解决金块问题? • 从两个简单实例谈起: • 假设只有一个金块,重10克,则不需要比较轻重, 最重者和最轻者是同一个金块。即比较0次。 • (2) 假设有2个金块,一个重10克,另一个重16克,则 • 需要比较1次,可以把最重者和最轻者确定下来。 • (3) 当有多个金块时(假设6块),则用二分法对其分 • 解,直到分解为(1)或(2)的情形时,问题很 • 容易解决。
第4讲 分治法 假设6个金块重量如下(以找最轻金块为例): 2 6 4 3 8 1 一分为二(两组): 【2 6 4】【3 8 1】 一分为二(四组): 【2 6】【4】【3 8】【1】 解较小子问题: 2 4 3 1 合并子问题解: 2 1 lmin rmin < ?
第4讲 分治法 课堂练习:假设6个金块重量如下:找最重者 2 6 4 3 8 1 一分为二(两组): 【2 6 4】【3 8 1】 一分为二(四组): 【2 6】【4】【3 8】【1】 解较小子问题: 合并子问题解: lmax rmax < ?
第4讲 分治法 用二分法解决金块问题算法设计: 问题抽象、简化为:在n个元素的集合中寻找最大和最小值元素。 (1)将集合一分为二,变为两个集合,目的是在较小的两个集合中分别找最大、最小元素。 (2)递归分解较小集合,直到每个集合中的元素个数≤2,然后找出小集合的最大、最小元素。 (3)合并(回溯):自低向上把子问题的解合并,大元素中取最大者,小元素中取最小者,最后得到元问题的解。
第4讲 分治法 用二分法解决金块问题算法描述: Float a[n]; Maxmin(int I,int j,float &fmax,float &fmin) {int mid; float lmax,lmin,rmax,rmin; if (i=j) {fmax=a[i];fmin=a[i];} i j
第4讲 分治法 用二分法解决金块问题算法描述(续): else if (i=j-1) if(a[i]<a[j]) {fmax=a[j];fmin=a[i];} else {fmax=a[j];fmin=a[i];} else //i<>j-1 {mid=[(i+j)/2];//[x]表示取整数 maxmin(i,mid,lmax,lmin); i j … i j mid
第4讲 分治法 用二分法解决金块问题算法描述(续): maxmin(mid+1,j,rmax,rmin); if (lmax>rmax) fmax=lmax; else fmax=rmax; if (lmin>rmin) fmin=rmin; else fmin=lmin; } } 解合并: 大者取大, 小者取小
第4讲 分治法 用二分法解决金块问题算法分析: 以元素比较总次数作为maxmin算法的时间复杂度度量指标,用T(n)表示比较总次数,则可以推导出递归关系: T(n)下界为
第4讲 分治法 对T(n)推导: 整理 整理 T(2)=1 整理
第4讲 分治法 课外研究: (1)学有余力的同学把金块问题递归算法改写为非递归算法,并分析算法的时间复杂性,然后和书上递归算法进行比较。 (2)学有余力的同学深入理解p142”算法分析2”。 (3)学有余力的同学设计程序,实现递归和非递归算法,上机实际测试运行时间上的差别。
第4讲 分治法 小结: (1)分治法的思想就是把大问题逐步分解为小问题……直到可解的小问题,最后把小问题的解逐层合并,得到大问题的解。 (2)二分法是最简单的分治法,每次把问题一分为二。
第4讲 分治法 作业: (1)预习p143-145 (2) p189,习题5,6,9
That’s all for today See you next time Good bye!