高级本分治应用2.docx
- 文档编号:6751179
- 上传时间:2023-01-10
- 格式:DOCX
- 页数:18
- 大小:65.21KB
高级本分治应用2.docx
《高级本分治应用2.docx》由会员分享,可在线阅读,更多相关《高级本分治应用2.docx(18页珍藏版)》请在冰豆网上搜索。
高级本分治应用2
第四章分治应用
分治习题集
4.1取余运算
源程序名mod.?
?
?
(pas,c,cpp)
可执行文件名mod.exe
输入文件名mod.in
输出文件名mod.out
【问题描述】
输入b,p,k的值,求bpmodk的值。
其中b,p,k*k为长整型数。
【样例】
mod.inmod.out
21092^10mod9=7
【知识准备】
进制转换的思想、二分法。
【算法分析】
本题主要的难点在于数据规模很大(b,p都是长整型数),对于bp显然不能死算,那样的话时间复杂度和编程复杂度都很大。
下面先介绍一个原理:
a*bmodk=(amodk)*(bmodk)modk。
显然有了这个原理,就可以把较大的幂分解成较小的,因而免去高精度计算等复杂过程。
那么怎样分解最有效呢?
显然对于任何一个自然数P,有p=2*pdiv2+pmod2,如19=2*19div2十19mod2=2*9+1,利用上述原理就可以把b的19次方除以k的余数转换为求b的9次方除以k的余数,即b19=b2*9+1=b*b9*b9,再进一步分解下去就不难求得整个问题的解。
这是一个典型的分治问题,具体实现的时候是用递推的方法来处理的,如p=19,有19=2*9+1,9=2*4+1,4=2*2+0,2=2*1+0,1=2*0+1,反过来,我们可以从0出发,通过乘以2再加上一个0或1而推出1,2,4,9,19,这样就逐步得到了原来的指数,进而递推出以b为底,依次以这些数为指数的自然数除以k的余数。
不难看出这里每一次乘以2后要加的数就是19对应的二进制数的各位数字,即1,0,0,1,1,而19=(10011)2,求解的过程也就是将二进制数还原为十进制数的过程。
具体实现请看下面的程序,程序中用数组binary存放p对应的二进制数,总位数为len,binary[1]存放最底位。
变量rest记录每一步求得的余数。
4.2地毯填补问题
源程序名blank.?
?
?
(pas,c,cpp)
可执行文件名blank.exe
输入文件名blank.in
输出文件名blank.out
【问题描述】
相传在一个古老的阿拉伯国家里,有一座宫殿。
宫殿里有个四四方方的格子迷宫,国王选择驸马的方法非常特殊,也非常简单:
公主就站在其中一个方格子上,只要谁能用地毯将除公主站立的地方外的所有地方盖上,美丽漂亮聪慧的公主就是他的人了。
公主这一个方格不能用地毯盖住,毯子的形状有所规定,只能有四种选择(如图4-l):
(1)
(2)(3)(4)
并且每一方格只能用一层地毯,迷宫的大小为(2k)2的方形。
当然,也不能让公主无限制的在那儿等,对吧?
由于你使用的是计算机,所以实现时间为1s。
【输入】
输入文件共2行。
第一行:
k,即给定被填补迷宫的大小为2k(0 第二行: xy,即给出公主所在方格的坐标(x为行坐标,y为列坐标),x和y之间有一个空格隔开。 【输出】 将迷宫填补完整的方案: 每一补(行)为xyc(x,y为毯子拐角的行坐标和列坐标,c为使用毯子的形状,具体见上面的图1,毯子形状分别用1、2、3、4表示,x、y、c之间用一个空格隔开)。 【样例】 blank.inblank.out 3551 33224 114 143 412 441 273 154 183 363 481 722 514 632 812 841 771 661 583 852 881 【知识准备】 分治思想和递归程序设计。 【算法分析】 拿到这个问题后,便有一种递归重复的感觉。 首先对最简单的情况(即k=1)进行分析: 公主只会在4个方格中的一个: 左上角: 则使用3号毯子补,毯子拐角坐标位于(2,2);{下面就简称为毯子坐标} 左下角: 则使用2号毯子补,毯子拐角坐标位于(1,2); 右上角: 则使用1号毯子补,毯子拐角坐标位于(2,1); 右下角: 则使用4号毯子补,毯子拐角坐标位于(1,1); 其实这样不能说明什么问题,但是继续讨论就会有收获,即讨论k=2的情况(如图4-1): # # # ● # ○ # # # ○ ○ # # # # # 我们假设公主所在的位置用实心圆表示,即上图中的(1,4),那么我们就可以把1号毯子放在(2,3)处,这样就将(1,3)至(2,4)的k=1见方全部覆盖(#表示地毯)。 接下来就是3个k=1的见方继续填满,这样问题就归结为k=1的情况了,但是有一点不同的是: 没有“公主”了,每一个k=1的小见方都会留下一个空白(即上图中的空心圆),那么空白就有: 1*3=3个,组合后便又是一个地毯形状。 好了,现在有感觉了吧,我们用分治法来解决它! 对于任意k>1的宫殿,均可以将其化分为4个k/2大小的宫殿,先看一下公主站的位置是属于哪一块,因为根据公主所在的位置,我们可以确定中间位置所放的毯子类型,再递归处理公主所站的那一块,直到出现边界条件k=1的情况,然后在公主边上铺上一块合适的地毯,递归结束。 由于要递归到每一格,复杂度就是面积,就是O(22*k*k)。 4.3平面上的最接近点对 源程序名nearest.? ? ? (pas,c,cpp) 可执行文件名nearest.exe 输入文件名nearest.in 输出文件名nearest.out 【问题描述】 给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的。 【输入】 第一行: n;2≤n≤60000 接下来n行: 每行两个实数: xy,表示一个点的行坐标和列坐标,中间用一个空格隔开。 【输出】 仅一行,一个实数,表示最短距离,精确到小数点后面4位。 【样例】 nearest.innearest.out 31.0000 11 12 22 【参考程序】 中位数、解析几何、时间复杂度、二分法 【算法分析】 如果n很小,那么本题很容易。 我们只要将每一点对于其它n-1个点的距离算出,找出最小距离即可。 时间复杂度O(n2)。 但本题n很大,显然会超时。 所以我们要寻找更快的解决问题的方法。 我们首先想到能不能缩小计算的规模,即把n个点的问题分治成一些小规模的问题呢? 由于二维情况下的问题计算过于复杂,所以先讨论一维的情况,假设点集为S。 我们用X轴上某个点m将点集S划分为2个子集S1和S2,使得S1={x∈S|x≤m};S2={x∈S|x>m}。 这样一来,对于所有p∈S1和q∈S2有p 递归地在S1和S2上找出其最接近的点对{p1,p2}和{q1,q2},并设δ=MIN{|p2-p1|,|q2-q1|},S中的最接近点对或者是{p1,p2},或者是{q1,q2},或者是某个{p3,q3},其中p3∈S1且q3∈S2。 如图4-2所示: 图4-2一维情形的分治法 我们注意到,如果S的最接近点对是{p3,q3},即|p3-q3|<δ,则p3和q3两者与m的距离不超过δ,即|p3-m|<δ,|q3-m|<δ,也就是说,p3∈(m-δ,m),q3∈(m,m+δ)。 由于每个长度为δ的半闭区间至多包含S1中的一个点,并且m是S1和S2的分割点,因此(m-δ,m)中至多包含S中的一个点,则此点就是S1中的最大点。 同理,如果(m-δ,m)中有S中的点,则此点就是S2中最小点。 因此,我们用线性时间就可以将S1的解和S2的解合并成为S的解。 也就是说,按这种分治策略,合并可在O(n)时间内完成。 这样是否就可以得到一个有效算法了呢? 还有一个问题有待解决,即分割点m的选择,即S1和S2的划分。 选取分割点m的一个基本要求是由此导出集合S的一个线性分割,即S=S1∪S2,S1≠φ,S2≠φ,且S1∈{x|x≤m},S2∈{x|x>m}。 容易看出,如果选取m=(MAX(S)+MIN(S))/2,可以满足线性分割的要求。 选取分割点后,再用O(n)时间即可将S划分成S1={x∈S|x≤m}和S2={x∈S|x>m}。 然而,这样选取分割点m,有可能造成划分出的子集S1和S2的不平衡。 例如在最坏情况下,S1只有1个,S2有n-1个,由此产生的分治在最坏情况下所需的时间T(n)应满足递归方程: T(n)=T(n-1)+O(n) 它的解是T(n)=O(n2)。 这种效率降低的现象可以通过分治中“平衡子问题”的方法加以解决。 也就是说,我们可以通过适当选择分割点m,使S1和S2中有大致相等个数的点。 自然地,我们会想到用S的n个点的坐标的中位数来作分割点。 这样一来,我们就能在O(n)的时间里确定m(证明略),从而得到效率相对较高的分割点。 至此,我们可以设计出一个求一维点集S中最接近点对的距离的算法: Functionnpair1(S); Begin IfS中只有2个点 Thenδ: =|x[2]-x[1]| ElseifS中只有1个点Thenδ: =∞ Elsebegin M: =S中各点的坐标值的中位数; 构造S1和S2;{S1∈{x|x≤m},S2∈{x|x>m}} δ1: =npair1(S1);δ2: =npair1(S2); P: =max(S1);Q: =min(S2); δ: =min(δ1,δ2,q-p); end; Exit(δ) End; 由以上的分析可知,该算法的分割步骤总共耗时O(n)。 因此,算法耗费的计算时间T(n)满足递归方程: T (2)=1 T(n)=2T(n/2)+O(n); 解此递归方程可得T(n)=O(n*Log2n)。 这个一维问题的算法看上去比用排序加扫描更加复杂,然而它可以推广到二维。 假设S为平面上的点集,每个点都有2个坐标值x和y。 为了将点集S线性分割为大小大致相等的2个子集S1和S2,我们选取一垂直线l: x=m来作为分割直线。 其中m为S中各点X坐标的中位数。 由此将S分割为S1={p∈S|x(p)≤m}和S2={p∈S|x(p)>m}。 从而使S1和S2分别位于直线l的左侧和右侧,且S=S1∪S2。 由于m是S中各点X坐标值的中位数,因此S1和S2中的点数大致相等。 递归地在S1和S2上求解最接近点对问题,我们分别得到S1和S2中的最小距离δ1和δ2。 现设δ=min(δ1,δ2)。 若S的最接近点对(p,q)之间的距离d(p,q)<δ,则p和q必分属于S1和S2。 不妨设p∈S1,q∈S2。 那么,p和q距直线L的距离均小于δ。 因此,我们若用P1和P2分别表示直线L的左边和右边的宽为δ的2个垂直长条,则p∈P1且q∈P2,如图4-3所示: 据直线L的距离小于δ的所有点 在一维的情形下,距分割点距离为δ的2个区间(m-δ,m),(m,m+δ)中最多各有S中一个点,因而这2点成为惟一的未检查过的最接近点对候选者。 二维的情形则要复杂一些,此时,P1中所有点与P2中所有点构成的点对均为最接近点对的候选者。 在最坏情况下有 对这样的候选者。 但是P1和P2中的点具有以下的稀疏性质,它使我们不必检查所有这 对候选者。 考虑P1中任意一点p,它若与P2中的点q构成最接近点对的候选者,则必有d(p,q)<δ。 满足这个条件的P2中的点有多少个呢? 容易看出这样的点一定落在一个δ*2δ的矩形R中(如图4-4所示)。 由δ的意义可知,P2中任何2个S中的点的距离都不小于δ。 由此而来可以推出矩形R中最多只有6个δ/2*2/3*δ的矩形(如图4-5所示)。 图4-4包含点q的δ*2δ矩形R图4-5图4-6 若矩形R中有多于6个S中的点,则由鸽笼原理易知至少有一个δ/2*2/3*δ的小矩形中有2个以上S中的点。 设U,V是这样2个点,它们位于同一小矩形中,则: ≤ 因此, ≤ 。 这与δ的意义相矛盾。 也就是说矩形R中最多只有6个S中的点。 图4-6是矩形R中含有S中的6个点的极端情形。 由于这种稀疏性质,对于P1中任一点p,P2中最多只有6个点与它构成最接近点对的候选者。 因此,在分治的合并步骤中,我们最多需要检查 对候选者,而不是 对候选者。 这是否就意味着我们可以在O(n)时间内完成分治法的合并步骤呢? 现在还不能确定,因为我们还不知道要检查哪6个点。 为了解决这个问题,我们可以将p和P2中所有S2的点投影到垂线L上。 由于能与p点一起构成最接近点对候选者的S2中点一定在矩形R中,所以它们在直线L上的投影距p在L上投影点的距离小于δ。 由上面的分析可知,这种投影点最多只有6个。 因此,若将P1和P2中所有S的点按其Y坐标排好序,则对P1中所有点,对排好序的点列作一次扫描,就可以找出所有最接近点对的候选者,对P1中每一点最多只要检查P2中排好序的相继6个点。 至此,我们得出用分治法求二维最接近点对距离的算法: Functionnpair(s); Begin IfS中只有2个点 Thenδ: =S中这2点的距离 ElseifS中只有1个点 Thenδ: =∞ Elsebegin (1)m: =S中各点X坐标值的中位数; 构造S1和S2; (2)δ1: =npair1(S1); δ2: =npair1(S2); (3)δm: =min(δ1,δ2); (4)设P1是S1中距垂直分割线L的距离在δm之间的所有点组成的集合, P2是S2中距分割线L的距离在δm之间的所有点组成的集合。 将P1 和P2中的点依其Y坐标值从小到大排序,并设P1*和P2*是相应的已 排好序的点列; (5)通过扫描P1*,对于P1*中每个点检查P2*中与其距离在δm之内的所 有点(最多6个)可以完成合并。 当P1*中的扫描指针可在宽为2*δm 的一个区间内移动。 设δ1是按这种扫描方式找到的点对间的最小距 离; (6)δ: =min(δm,δt); end; Exit(δ) End; 下面我们来分析上述算法的时间复杂性。 设对于n个点的平面点集S,在 (1)和(5)步用了O(n)时间,(3)和(6)用的是常数时间, (2)则用了 时间,而在(4),最坏情况要O(nlog2n)时间,仍然无法承受,所以我们在整个程序的开始时,就先将S中的点对按Y座标值排序,这样一来(4)和(5)两步的时间就只需O(n)的时间了,所以总的计算时间同样满足: T (2)=1, 由此,该问题的时间复杂度为O(nlog2n),在渐进的意义下为最优算法了。 空间复杂度为O(n)。 4.4求方程的根 源程序名equation.? ? ? (pas,c,cpp) 可执行文件名equation.exe 输入文件名equation.in 输出文件名equation.out 【问题描述】 输入m,n,p,a,b,求方程f(x)=mx+nx-px=0在[a,b]内的根。 m,n,p,a,b均为整数,且a 如果有根,则输出,精确到1E-11;如果无方程根,则输出“NO”。 【样例】 equation.inequation.out 234121.5071265916E+00 2.9103830457E-11 【算法分析】 首先这是一个单调递增函数,对于一个单调递增(或递减)函数,如图4-7所示,判断在[a,b]范围内是否有解,解是多少。 方法有多种,常用的一种方法叫“迭代法”,也就是“二分法”。 先判断f(a)·f(b)≤0,如果满足则说明在[a,b]范围内有解,否则无解。 如果有解再判断x=(a+b)/2是不是解,如果是则输出解结束程序,否则我们采用二分法,将范围缩小到[a,x)或(x,b],究竟在哪一半区间里有解,则要看是f(a)·f(x)<0还是f(x)·f(b)<0。 当然对于yx,我们需要用换底公式把它换成exp(xln(y))。 4.5小车问题 源程序名car.? ? ? (pas,c,cpp) 可执行文件名car.exe 输入文件名car.in 输出文件名car.out 【问题描述】 甲、乙两人同时从A地出发要尽快同时赶到B地。 出发时A地有一辆小车,可是这辆小车除了驾驶员外只能带一人。 已知甲、乙两人的步行速度一样,且小于车的速度。 问: 怎样利用小车才能使两人尽快同时到达。 【输入】 仅一行,三个数据分别表示AB两地的距离s,人的步行速度a,车的速度b。 【输出】 两人同时到达B地需要的最短时间。 【样例】 car.incar.out 1205259.6000000000E+00 【算法分析】 最佳方案为: 甲先乘车到达K处后下车步行,小车再回头接已走到C处的乙,在D处相遇后,乙再乘车赶往B,最后甲、乙一起到达B地。 这样问题就转换成了求K处的位置,我们用二分法,不断尝试,直到满足同时到达的时间精度。 算法框架如下: (1)输入s,a,b; (2)c0: =0;c1: =s;c: =(c0+c1)/2; (3)求t1,t2; (4)如果t1 =(c0+c)/2 否则c: =(c+c1)/2; 反复执行(3)和(4),直到abs(t1-t2)满足精度要求(即小于误差标准)。 4.6黑白棋子的移动 源程序名chessman.? ? ? (pas,c,cpp) 可执行文件名chessman.exe 输入文件名chessman.in 输出文件名chessman.out 【问题描述】 有2n个棋子(n≥4)排成一行,开始为位置白子全部在左边,黑子全部在右边,如下图为n=5的情况: ○○○○○●●●●● 移动棋子的规则是: 每次必须同时移动相邻的两个棋子,颜色不限,可以左移也可以右移到空位上去,但不能调换两个棋子的左右位置。 每次移动必须跳过若干个棋子(不能平移),要求最后能移成黑白相间的一行棋子。 如n=5时,成为: ○●○●○●○●○● 任务: 编程打印出移动过程。 【样例】 chessman.inchessman.out 7step0: ooooooo*******-- step1: oooooo--******o* step2: oooooo--******o* step3: ooooo--*****o*o* step4: ooooo*****--o*o* step5: oooo--****o*o*o* step6: oooo****--o*o*o* step7: ooo--***o*o*o*o* step8: ooo*o**--*o*o*o* step9: o--*o**oo*o*o*o* step10: o*o*o*--o*o*o*o* step11: --o*o*o*o*o*o*o* 【问题分析】 我们先从n=4开始试试看,初始时: ○○○○●●●● 第1步: ○○○——●●●○●(—表示空位) 第2步: ○○○●○●●——● 第3步: ○——●○●●○○● 第4步: ○●○●○●——○● 第5步: ——○●○●○●○● 如果n=5呢? 我们继续尝试,希望看出一些规律,初始时: ○○○○○●●●●● 第1步: ○○○○——●●●●○● 第2步: ○○○○●●●●——○● 这样,n=5的问题又分解成了n=4的情况,下面只要再做一下n=4的5个步骤就行了。 同理,n=6的情况又可以分解成n=5的情况,……,所以,对于一个规模为n的问题,我们很容易地就把它分治成了规模为n-1的相同类型子问题。 数据结构如下: 数组c[1..max]用来作为棋子移动的场所,初始时,c[1]~c[n]存放白子(用字符o表示),c[n+1]~c[2n]存放黑子(用字符*表示),c[2n+1],c[2n+2]为空位置(用字符—表示)。 最后结果在c[3]~c[2n+2]中。 4.7麦森数(NOIP2003) 源程序名mason.? ? ? (pas,c,cpp) 可执行文件名mason.exe 输入文件名mason.in 输出文件名mason.out 【问题描述】 形如2p-1的素数称为麦森数,这时P一定也是个素数。 但反过来不一定,即如果P是个素数,2p-1不一定也是素数。 到1998年底,人们已找到了37个麦森数。 最大的一个是P=3021377,它有909526位。 麦森数有许多重要应用,它与完全数密切相关。 任务: 从文件中输入P(1000 【输入】 文件中只包含一个整数P(1000 【输出】 第一行: 十进制高精度数2p-1的位数; 第2~11行: 十进制高精度数2p-1的最后500位数字(每行输出50位,共输出10行,不足500位时高位补0); 不必验证2p-1与P是否为素数。 【样例】 mason.in 1279 mason.out 386 00000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000 00000000000000104079321946643990819252403273640855 38615262247266704805319112350403608059673360298012 23944173232418484242161395428100779138356624832346 49081399066056773207629241295093892203457731833496 61583550472959420547689811211693677147548478866962 50138443826029173234888531116082853841658502825560 46662248318909188018470682222031405210266984354887 32958028878050869736186900714720710555703168729087 【问题分析】 本题的解题方法很多,其中分治也是一种巧妙的方法。 首先可以想到: 2n=(2ndiv2)2*2nmod2,即: 如果要计算2n,就要先算出2ndiv2,然后用高精度乘法算它的
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 高级 分治 应用