分治和倍增解析.pptxVIP

  1. 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
  2. 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  3. 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
  4. 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
  5. 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们
  6. 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
  7. 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
分治合倍增 By DJ 什么是分治? 字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。 举个栗子 万一联赛时脑抽了,忘记algorithm怎么打了,该怎么快排呢?(假设你只忘单词没忘算法) 来个学霸讲讲快排原理? 也就是说,我们可以通过不断地将某一区间内的数分成比第一个数大的和比第一个数小的两部分,如此便可将整个区间分成两小份,继续对每一个区间进行quicksort操作,直到区间内只有两个数为止。 这便是分治了! 记得标题吗?“分治合”倍增 为什么是“合”呢?因为分治的骨架就是以下三步: 分:将问题分成n(一般n=2)个子问题; 治:解决子问题(可以继续分,或者小到一定规模后直接解决) 合:将n个子问题合并,最终得出原问题的解。 其中,分、治都很容易(难怪老说“分治很容易”,原来是没断句),真正难的地方在“合”。快排中因为分的时候就做合了的事了(大的在大的一边,小的在小的一边),所以不必再考虑事后的合,quicksort(**,**)后就可以直接接return了。 逆序对 讲到快排就想到归并排序,讲到归并排序就想到逆序对。 逆序对,说白了就是你在我后面你还比我小的一对数,如1 3 2中,3、2为一组逆序对。 直接朴素算法,不用讲了吧? 如何巧妙地算逆序对呢? 无序数列太乱,先从有序考虑。两个有序数对前后相接,逆序对怎么求? 那么把无序转化成有序呢? 讨论三步:分、治、合。 基本思路 我刚才说到了归并排序,那么我们能否在归并排序时做点手脚,顺便记录逆序对呢? 答案是肯定的! 在两个有序数列归并时,设两个指针,从后往前遍历,当搜到后列当前元素小于前排当前元素时,则说明前列指针及它后面的元素均组成逆序对,加入answer中。 又来个栗子 1 3 5 7 9 2 4 6 8 10 +4 +3 +2 +1 伪代码: Void ni(int l, int r) { if(l==r)return; If(r-l==1){if(本身为逆序对){ans++;交换位置;}return;}//治 Int mid=(l+r)/2; Ni(l,mid);mi(mid+1,r);//分 把两个有序数列a[l..mid]、a[mid+1..r]归并排序同时求逆序对; Return; } 补充一点 逆序对还有一个树状数组算法,复杂度取决于数列的极差,在数列长极差小时候会比分治法快一点,且不容易被卡常数,可以视作分治法的互补算法,同学们可自行学习。 平面内最近点对 问题:给出n个点的坐标(x,y),求出最近两点的距离(4位小数)。 能用分治法算一维吗? 能不能将其拓展到二维呢? 讨论如何设计三步:分、治、合。 一维时: 区间中位线? 点的坐标的中位数? 如何分? 特殊情况下分了等于没分。 显然这货更好! 合? 2、3号点的距离! 二维呢? 一维启示我们:要按照坐标中位数来分,效果最好。 合? 分治很容易,真的很容易,但……合呢? 一维启示我们:可以把整个平面分成两部分(分),直到只剩2个点,返回它们的距离;或3个点,两两比较(治),再将两边的m1、m2中的最小值m和交界处附近的点的最近距离m0比较,返回最小值M。 初步伪代码 Int zjdd(点集s) //不会STL的可试着数组模拟,可加数组元素个数为参数 { if(规模足够小)return 解决方案; 遍历点集的x,获得中位数mid; 再次遍历,分出x=mid左边的点集s1和x=mid右边上的点集s2; int m=min(zddd(s1),zjdd(s2)); 找到x=mid附近点的最近距离m0; return min(m,m0); } 如何合呢? 合之前,我们已经找到每一个子问题中最近距离m了,显然与x=mid距离大于等于m的点是无论如何也找不到更优解的。于是我们确定了范围:x∈(mid-m,mid+m)。 运气不好的话,可能会囊括所有点(比如集中在一条平行于y轴上的线上,s1=?,s2=?,结果我们等于没分)。这些点之间难道又要爆搜吗? 显然不必,否则我就直接过了。 我们可以设范围内x=mid左边点集为p1,其他为p2,mid既在p1内又在p2内。可以发现,除非p1中的点在x=mid上未被考虑过,否则它们之间的距离都大于等于m。所以,我们可以对p1内每一个点进行考虑,如果不在mid上,易证可能存在的更优解在p2中且位于以这个点为圆心m为半径的圆内。但圆内的坐标判断太烦人,干脆把圆扩充成矩形,看着顺眼,判得容易。 有人要问了:把圆扩大成矩形,不是会增加更多点,增大复杂度吗? 事实上

文档评论(0)

tt435678 + 关注
实名认证
文档贡献者

该用户很懒,什么也没介绍

1亿VIP精品文档

相关文档